Merge "Upgrade to AGP 8.9.0-beta01" into androidx-main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 10afede..9a7562d 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -2,6 +2,7 @@
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 ktfmt_hook = ${REPO_ROOT}/frameworks/support/development/ktfmt.sh --skip-if-empty --file=${PREUPLOAD_FILES_PREFIXED}
 warn_check_api = ${REPO_ROOT}/frameworks/support/development/apilint.py -f ${PREUPLOAD_FILES}
+relnote_required_runtime = ${REPO_ROOT}/frameworks/support/development/requirerelnote.py --module /androidx/compose/runtime/  --commit ${PREUPLOAD_COMMIT_MESSAGE} --file ${PREUPLOAD_FILES}
 
 [Builtin Hooks]
 commit_msg_changeid_field = true
diff --git a/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionSchemaDefinition.kt b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionSchemaDefinition.kt
new file mode 100644
index 0000000..3469992
--- /dev/null
+++ b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/AppFunctionSchemaDefinition.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions
+
+import androidx.annotation.RestrictTo
+import androidx.annotation.RestrictTo.Scope
+
+/**
+ * Annotates an interface defining the schema for an app function, outlining its input, output, and
+ * behavior
+ *
+ * Example Usage:
+ * ```kotlin
+ * @AppFunctionSchemaDefinition(name = "findNotes", version = 1, category = "Notes")
+ * interface FindNotes {
+ *   suspend fun findNotes(
+ *     appFunctionContext: AppFunctionContext,
+ *     findNotesParams: FindNotesParams,
+ *   ): List<Note>
+ * }
+ * ```
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
+@Retention(
+    // Binary because it's used to determine the annotation values from the compiled schema library.
+    AnnotationRetention.BINARY
+)
+@Target(AnnotationTarget.CLASS)
+public annotation class AppFunctionSchemaDefinition(
+    val name: String,
+    val version: Int,
+    val category: String
+)
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/internal/Constants.kt
similarity index 60%
copy from navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
copy to appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/internal/Constants.kt
index 469b038..d8cd558 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
+++ b/appfunctions/appfunctions-common/src/main/java/androidx/appfunctions/internal/Constants.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.navigation
+package androidx.appfunctions.internal
 
-/** @see NavController.enableDeepLinkSaveState */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.FUNCTION)
-@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
-public annotation class NavDeepLinkSaveStateControl
+import androidx.annotation.RestrictTo
+
+/** Reusable constants values for AppFunction. */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public object Constants {
+    /** Android Log tag for AppFunction logs. */
+    public const val APP_FUNCTIONS_TAG: String = "AppFunctions"
+}
diff --git a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/AppFunctionCompiler.kt b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/AppFunctionCompiler.kt
index 6151d45..8acc8bc 100644
--- a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/AppFunctionCompiler.kt
+++ b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/AppFunctionCompiler.kt
@@ -20,6 +20,7 @@
 import androidx.appfunctions.compiler.core.logException
 import androidx.appfunctions.compiler.processors.AppFunctionIdProcessor
 import androidx.appfunctions.compiler.processors.AppFunctionInventoryProcessor
+import androidx.appfunctions.compiler.processors.AppFunctionLegacyIndexXmlProcessor
 import com.google.devtools.ksp.processing.KSPLogger
 import com.google.devtools.ksp.processing.Resolver
 import com.google.devtools.ksp.processing.SymbolProcessor
@@ -53,8 +54,11 @@
         override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
             val idProcessor = AppFunctionIdProcessor(environment.codeGenerator)
             val inventoryProcessor = AppFunctionInventoryProcessor(environment.codeGenerator)
+            // TODO: Add compiler option to disable legacy xml generator.
+            val legacyIndexXmlProcessor =
+                AppFunctionLegacyIndexXmlProcessor(environment.codeGenerator)
             return AppFunctionCompiler(
-                listOf(idProcessor, inventoryProcessor),
+                listOf(idProcessor, inventoryProcessor, legacyIndexXmlProcessor),
                 environment.logger,
             )
         }
diff --git a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/AppFunctionSymbolResolver.kt b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/AppFunctionSymbolResolver.kt
index 2bac5ac..e8ae1c5 100644
--- a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/AppFunctionSymbolResolver.kt
+++ b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/AppFunctionSymbolResolver.kt
@@ -20,7 +20,11 @@
 import androidx.appfunctions.compiler.core.IntrospectionHelper.AppFunctionAnnotation
 import com.google.devtools.ksp.processing.Resolver
 import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFile
 import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.google.devtools.ksp.symbol.KSTypeReference
+import com.google.devtools.ksp.symbol.KSValueParameter
+import com.squareup.kotlinpoet.LIST
 
 /** The helper class to resolve AppFunction related symbols. */
 class AppFunctionSymbolResolver(private val resolver: Resolver) {
@@ -99,7 +103,30 @@
         }
 
         private fun validateParameterTypes() {
-            // TODO: Validate that the parameter type used by the app functions are supported
+            for (appFunctionDeclaration in appFunctionDeclarations) {
+                for ((paramIndex, ksValueParameter) in
+                    appFunctionDeclaration.parameters.withIndex()) {
+                    if (paramIndex == 0) {
+                        // Skip the first parameter which is always the `AppFunctionContext`.
+                        continue
+                    }
+
+                    if (!ksValueParameter.validateAppFunctionParameterType()) {
+                        throw ProcessingException(
+                            "App function parameters must be one of the following " +
+                                "primitive types or a list of these types:\n${
+                                SUPPORTED_RAW_PRIMITIVE_TYPES.joinToString(
+                                    ",\n"
+                                )
+                            }, but found ${
+                                    ksValueParameter.resolveTypeReference().ensureQualifiedTypeName()
+                                        .asString()
+                            }",
+                            ksValueParameter
+                        )
+                    }
+                }
+            }
         }
 
         /**
@@ -113,5 +140,57 @@
             val methodName = functionDeclaration.simpleName.asString()
             return "${packageName}.${className}#${methodName}"
         }
+
+        /** Returns the file containing the class declaration and app functions. */
+        fun getSourceFile(): KSFile? = classDeclaration.containingFile
+
+        private fun KSValueParameter.validateAppFunctionParameterType(): Boolean {
+            // Todo(b/391342300): Allow AppFunctionSerializable type too.
+            if (type.isOfType(LIST)) {
+                val typeReferenceArgument = type.resolveListParameterizedType()
+                // List types only support raw primitive types
+                return SUPPORTED_RAW_PRIMITIVE_TYPES.contains(
+                    typeReferenceArgument.ensureQualifiedTypeName().asString()
+                )
+            }
+            return SUPPORTED_RAW_PRIMITIVE_TYPES.contains(
+                type.ensureQualifiedTypeName().asString()
+            ) || SUPPORTED_ARRAY_PRIMITIVE_TYPES.contains(type.ensureQualifiedTypeName().asString())
+        }
+
+        /**
+         * Resolves the type reference of a parameter.
+         *
+         * If the parameter type is a list, it will resolve the type reference of the list element.
+         */
+        private fun KSValueParameter.resolveTypeReference(): KSTypeReference {
+            return if (type.isOfType(LIST)) {
+                type.resolveListParameterizedType()
+            } else {
+                type
+            }
+        }
+
+        private companion object {
+            val SUPPORTED_RAW_PRIMITIVE_TYPES: Set<String> =
+                setOf(
+                    Int::class.qualifiedName!!,
+                    Long::class.qualifiedName!!,
+                    Float::class.qualifiedName!!,
+                    Double::class.qualifiedName!!,
+                    Boolean::class.qualifiedName!!,
+                    String::class.qualifiedName!!,
+                )
+
+            val SUPPORTED_ARRAY_PRIMITIVE_TYPES: Set<String> =
+                setOf(
+                    IntArray::class.qualifiedName!!,
+                    LongArray::class.qualifiedName!!,
+                    FloatArray::class.qualifiedName!!,
+                    DoubleArray::class.qualifiedName!!,
+                    BooleanArray::class.qualifiedName!!,
+                    ByteArray::class.qualifiedName!!,
+                )
+        }
     }
 }
diff --git a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/IntrospectionHelper.kt b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/IntrospectionHelper.kt
index fe0d3fa..694a061 100644
--- a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/IntrospectionHelper.kt
+++ b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/IntrospectionHelper.kt
@@ -28,6 +28,18 @@
     // Annotation classes
     object AppFunctionAnnotation {
         val CLASS_NAME = ClassName(APP_FUNCTIONS_PACKAGE_NAME, "AppFunction")
+        const val PROPERTY_IS_ENABLED = "isEnabled"
+    }
+
+    object AppFunctionSchemaDefinitionAnnotation {
+        val CLASS_NAME = ClassName(APP_FUNCTIONS_PACKAGE_NAME, "AppFunctionSchemaDefinition")
+        const val PROPERTY_CATEGORY = "category"
+        const val PROPERTY_NAME = "name"
+        const val PROPERTY_VERSION = "version"
+    }
+
+    object AppFunctionSerializableAnnotation {
+        val CLASS_NAME = ClassName(APP_FUNCTIONS_PACKAGE_NAME, "AppFunctionSerializable")
     }
 
     // Classes
diff --git a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/KspUtils.kt b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/KspUtils.kt
index 1fa4707..65af037 100644
--- a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/KspUtils.kt
+++ b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/core/KspUtils.kt
@@ -16,8 +16,31 @@
 
 package androidx.appfunctions.compiler.core
 
+import com.google.devtools.ksp.symbol.KSAnnotation
+import com.google.devtools.ksp.symbol.KSName
 import com.google.devtools.ksp.symbol.KSTypeReference
 import com.squareup.kotlinpoet.ClassName
+import com.squareup.kotlinpoet.LIST
+import kotlin.reflect.KClass
+import kotlin.reflect.cast
+
+/**
+ * Resolves the type reference to the parameterized type if it is a list. Otherwise, it returns the
+ * type reference as is.
+ *
+ * @return the resolved type reference
+ * @throws ProcessingException If unable to resolve the type.
+ */
+fun KSTypeReference.resolveListParameterizedType(): KSTypeReference {
+    if (!isOfType(LIST)) {
+        throw ProcessingException(
+            "Unable to resolve list parameterized type for non list type",
+            this
+        )
+    }
+    return resolve().arguments.firstOrNull()?.type
+        ?: throw ProcessingException("Unable to resolve the parameterized type for the list", this)
+}
 
 /**
  * Checks if the type reference is of the given type.
@@ -27,12 +50,45 @@
  * @throws ProcessingException If unable to resolve the type.
  */
 fun KSTypeReference.isOfType(type: ClassName): Boolean {
-    val ksType = this.resolve()
-    val typeName =
-        ksType.declaration.qualifiedName
-            ?: throw ProcessingException(
-                "Unable to resolve the type to check if it is of type [${type}]",
-                this
-            )
+    val typeName = ensureQualifiedTypeName()
     return typeName.asString() == type.canonicalName
 }
+
+/**
+ * Finds and returns an annotation of [annotationClass] type.
+ *
+ * @param annotationClass the annotation class to find
+ */
+fun Sequence<KSAnnotation>.findAnnotation(annotationClass: ClassName): KSAnnotation? =
+    this.singleOrNull {
+        val shortName = it.shortName.getShortName()
+        if (shortName != annotationClass.simpleName) {
+            false
+        } else {
+            val typeName = it.annotationType.ensureQualifiedTypeName()
+            typeName.asString() == annotationClass.canonicalName
+        }
+    }
+
+/**
+ * Resolves the type reference to its qualified name.
+ *
+ * @return the qualified name of the type reference
+ */
+fun KSTypeReference.ensureQualifiedTypeName(): KSName =
+    resolve().declaration.qualifiedName
+        ?: throw ProcessingException(
+            "Unable to resolve the qualified type name for this reference",
+            this
+        )
+
+/** Returns the value of the annotation property if found. */
+fun <T : Any> KSAnnotation.requirePropertyValueOfType(
+    propertyName: String,
+    expectedType: KClass<T>,
+): T {
+    val propertyValue =
+        this.arguments.singleOrNull { it.name?.asString() == propertyName }?.value
+            ?: throw ProcessingException("Unable to find property with name: $propertyName", this)
+    return expectedType.cast(propertyValue)
+}
diff --git a/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/processors/AppFunctionLegacyIndexXmlProcessor.kt b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/processors/AppFunctionLegacyIndexXmlProcessor.kt
new file mode 100644
index 0000000..d41a4d3e
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/main/java/androidx/appfunctions/compiler/processors/AppFunctionLegacyIndexXmlProcessor.kt
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions.compiler.processors
+
+import androidx.appfunctions.compiler.core.AppFunctionSymbolResolver
+import androidx.appfunctions.compiler.core.AppFunctionSymbolResolver.AnnotatedAppFunctions
+import androidx.appfunctions.compiler.core.IntrospectionHelper.AppFunctionAnnotation
+import androidx.appfunctions.compiler.core.IntrospectionHelper.AppFunctionSchemaDefinitionAnnotation
+import androidx.appfunctions.compiler.core.ProcessingException
+import androidx.appfunctions.compiler.core.findAnnotation
+import androidx.appfunctions.compiler.core.requirePropertyValueOfType
+import com.google.devtools.ksp.processing.CodeGenerator
+import com.google.devtools.ksp.processing.Dependencies
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration
+import com.squareup.kotlinpoet.ClassName
+import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.transform.OutputKeys
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.dom.DOMSource
+import javax.xml.transform.stream.StreamResult
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+
+/**
+ * Generates AppFunction's index xml file for the legacy AppSearch indexer to index.
+ *
+ * The generator would write an XML file as `/assets/app_functions.xml`. The file would be packaged
+ * into the APK's asset when assembled. So that the AppSearch indexer can look up the asset and
+ * inject metadata into platform AppSearch database accordingly.
+ *
+ * The new indexer will index additional properties based on the schema defined in SDK instead of
+ * the pre-defined one in AppSearch.
+ */
+class AppFunctionLegacyIndexXmlProcessor(
+    private val codeGenerator: CodeGenerator,
+) : SymbolProcessor {
+
+    override fun process(resolver: Resolver): List<KSAnnotated> {
+        generateLegacyIndexXml(AppFunctionSymbolResolver(resolver).resolveAnnotatedAppFunctions())
+        return emptyList()
+    }
+
+    /**
+     * Generates AppFunction's legacy index xml files for v1 indexer in App Search.
+     *
+     * @param appFunctionsByClass a collection of functions annotated with @AppFunction grouped by
+     *   their enclosing classes.
+     */
+    private fun generateLegacyIndexXml(
+        appFunctionsByClass: List<AnnotatedAppFunctions>,
+    ) {
+        if (appFunctionsByClass.isEmpty()) {
+            return
+        }
+        val xmlDetails = appFunctionsByClass.flatMap(::getAppFunctionXmlDetail)
+        writeXmlFile(xmlDetails, appFunctionsByClass)
+    }
+
+    private fun getAppFunctionXmlDetail(
+        appFunctionsByClass: AnnotatedAppFunctions
+    ): List<AppFunctionXmlDetails> {
+
+        return appFunctionsByClass.appFunctionDeclarations.map {
+            val appFunctionAnnotation =
+                it.annotations.findAnnotation(AppFunctionAnnotation.CLASS_NAME)
+                    ?: throw ProcessingException("Function not annotated with @AppFunction.", it)
+            val enabled =
+                appFunctionAnnotation.requirePropertyValueOfType(
+                    AppFunctionAnnotation.PROPERTY_IS_ENABLED,
+                    Boolean::class,
+                )
+
+            val schemaDetail = getAppFunctionSchemaDetail(it)
+
+            AppFunctionXmlDetails(
+                appFunctionsByClass.getAppFunctionIdentifier(it),
+                enabled,
+                schemaDetail,
+            )
+        }
+    }
+
+    private fun getAppFunctionSchemaDetail(
+        function: KSFunctionDeclaration
+    ): AppFunctionSchemaDetail? {
+        val rootInterfaceWithAppFunctionSchemaDefinition =
+            findRootInterfaceWithAnnotation(
+                function,
+                AppFunctionSchemaDefinitionAnnotation.CLASS_NAME
+            ) ?: return null
+
+        val schemaFunctionAnnotation =
+            rootInterfaceWithAppFunctionSchemaDefinition.annotations.findAnnotation(
+                AppFunctionSchemaDefinitionAnnotation.CLASS_NAME
+            ) ?: return null
+        val schemaCategory =
+            schemaFunctionAnnotation.requirePropertyValueOfType(
+                AppFunctionSchemaDefinitionAnnotation.PROPERTY_CATEGORY,
+                String::class,
+            )
+        val schemaName =
+            schemaFunctionAnnotation.requirePropertyValueOfType(
+                AppFunctionSchemaDefinitionAnnotation.PROPERTY_NAME,
+                String::class,
+            )
+        val schemaVersion =
+            schemaFunctionAnnotation.requirePropertyValueOfType(
+                AppFunctionSchemaDefinitionAnnotation.PROPERTY_VERSION,
+                Int::class,
+            )
+        return AppFunctionSchemaDetail(schemaCategory, schemaName, schemaVersion)
+    }
+
+    private fun findRootInterfaceWithAnnotation(
+        function: KSFunctionDeclaration,
+        annotationName: ClassName
+    ): KSClassDeclaration? {
+        val parentDeclaration = function.parentDeclaration as? KSClassDeclaration ?: return null
+
+        // Check if the enclosing class has the @AppFunctionSchemaDefinition
+        val annotation = parentDeclaration.annotations.findAnnotation(annotationName)
+        if (annotation != null) {
+            return parentDeclaration
+        }
+
+        val superClassFunction = (function.findOverridee() as? KSFunctionDeclaration) ?: return null
+        return findRootInterfaceWithAnnotation(superClassFunction, annotationName)
+    }
+
+    private fun writeXmlFile(
+        xmlDetailsList: List<AppFunctionXmlDetails>,
+        appFunctionsByClass: List<AnnotatedAppFunctions>,
+    ) {
+        val xmlDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+        val xmlDocument = xmlDocumentBuilder.newDocument().apply { xmlStandalone = true }
+
+        val appFunctionsElement = xmlDocument.createElement(XmlElement.APP_FUNCTIONS_ELEMENTS_TAG)
+        xmlDocument.appendChild(appFunctionsElement)
+
+        for (xmlDetails in xmlDetailsList) {
+            appFunctionsElement.appendChild(xmlDocument.createAppFunctionElement(xmlDetails))
+        }
+
+        val transformer =
+            TransformerFactory.newInstance().newTransformer().apply {
+                setOutputProperty(OutputKeys.INDENT, "yes")
+                setOutputProperty(OutputKeys.ENCODING, "UTF-8")
+                setOutputProperty(OutputKeys.VERSION, "1.0")
+                setOutputProperty(OutputKeys.STANDALONE, "yes")
+            }
+
+        codeGenerator
+            .createNewFile(
+                Dependencies(
+                    aggregating = true,
+                    *appFunctionsByClass.mapNotNull { it.getSourceFile() }.toTypedArray()
+                ),
+                XML_PACKAGE_NAME,
+                XML_FILE_NAME,
+                XML_EXTENSION
+            )
+            .use { stream -> transformer.transform(DOMSource(xmlDocument), StreamResult(stream)) }
+    }
+
+    private fun Document.createAppFunctionElement(xmlDetails: AppFunctionXmlDetails): Element =
+        createElement(XmlElement.APP_FUNCTION_ITEM_TAG).apply {
+            appendChild(
+                createElementWithTextNode(XmlElement.APP_FUNCTION_ID_TAG, xmlDetails.functionId)
+            )
+
+            val schemaDetail = xmlDetails.schemaDetail
+            if (schemaDetail != null) {
+                appendChild(
+                    createElementWithTextNode(
+                        XmlElement.APP_FUNCTION_SCHEMA_CATEGORY_TAG,
+                        schemaDetail.schemaCategory,
+                    )
+                )
+                appendChild(
+                    createElementWithTextNode(
+                        XmlElement.APP_FUNCTION_SCHEMA_NAME_TAG,
+                        schemaDetail.schemaName,
+                    )
+                )
+                appendChild(
+                    createElementWithTextNode(
+                        XmlElement.APP_FUNCTION_SCHEMA_VERSION_TAG,
+                        schemaDetail.schemaVersion.toString(),
+                    )
+                )
+            }
+            appendChild(
+                createElementWithTextNode(
+                    XmlElement.APP_FUNCTION_ENABLE_BY_DEFAULT_TAG,
+                    xmlDetails.enabled.toString(),
+                )
+            )
+        }
+
+    private fun Document.createElementWithTextNode(elementName: String, text: String): Element =
+        createElement(elementName).apply { appendChild(createTextNode(text)) }
+
+    /** Details of an app function that are needed to generate its XML file. */
+    private data class AppFunctionXmlDetails(
+        val functionId: String,
+        val enabled: Boolean,
+        val schemaDetail: AppFunctionSchemaDetail?,
+    )
+
+    /** Details of an schema function that are needed to generate its XML file. */
+    private data class AppFunctionSchemaDetail(
+        val schemaCategory: String,
+        val schemaName: String,
+        val schemaVersion: Int,
+    )
+
+    private companion object {
+        private const val XML_PACKAGE_NAME = "assets"
+        private const val XML_FILE_NAME = "app_functions"
+        private const val XML_EXTENSION = "xml"
+
+        private object XmlElement {
+            const val APP_FUNCTIONS_ELEMENTS_TAG = "appfunctions"
+            const val APP_FUNCTION_ITEM_TAG = "appfunction"
+            const val APP_FUNCTION_ID_TAG = "function_id"
+            const val APP_FUNCTION_SCHEMA_CATEGORY_TAG = "schema_category"
+            const val APP_FUNCTION_SCHEMA_NAME_TAG = "schema_name"
+            const val APP_FUNCTION_SCHEMA_VERSION_TAG = "schema_version"
+            const val APP_FUNCTION_ENABLE_BY_DEFAULT_TAG = "enabled_by_default"
+        }
+    }
+}
diff --git a/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/AppFunctionCompilerTest.kt b/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/AppFunctionCompilerTest.kt
index 8860052..4204290 100644
--- a/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/AppFunctionCompilerTest.kt
+++ b/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/AppFunctionCompilerTest.kt
@@ -46,9 +46,9 @@
     fun testSimpleFunction_genAppFunctionIds_success() {
         val report = compilationTestHelper.compileAll(sourceFileNames = listOf("SimpleFunction.KT"))
 
-        compilationTestHelper.assertSuccessWithContent(
+        compilationTestHelper.assertSuccessWithSourceContent(
             report = report,
-            expectGeneratedFileName = "SimpleFunctionIds.kt",
+            expectGeneratedSourceFileName = "SimpleFunctionIds.kt",
             goldenFileName = "SimpleFunctionIds.KT"
         )
     }
@@ -85,10 +85,40 @@
     fun testSimpleFunction_genAppFunctionInventoryImpl_success() {
         val report = compilationTestHelper.compileAll(sourceFileNames = listOf("SimpleFunction.KT"))
 
-        compilationTestHelper.assertSuccessWithContent(
+        compilationTestHelper.assertSuccessWithSourceContent(
             report = report,
-            expectGeneratedFileName = "SimpleFunction_AppFunctionInventory_Impl.kt",
+            expectGeneratedSourceFileName = "SimpleFunction_AppFunctionInventory_Impl.kt",
             goldenFileName = "$%s".format("SimpleFunction_AppFunctionInventory_Impl.KT")
         )
     }
+
+    @Test
+    fun testAllPrimitiveInputFunctions_genAppFunctionInventoryImpl_success() {
+        val report =
+            compilationTestHelper.compileAll(
+                sourceFileNames = listOf("AllPrimitiveInputFunctions.KT")
+            )
+
+        compilationTestHelper.assertSuccessWithSourceContent(
+            report = report,
+            expectGeneratedSourceFileName =
+                "AllPrimitiveInputFunctions_AppFunctionInventory_Impl.kt",
+            goldenFileName = "$%s".format("AllPrimitiveInputFunctions_AppFunctionInventory_Impl.KT")
+        )
+    }
+
+    // TODO: Add more tests for legacy index processor.
+    @Test
+    fun testSampleNoParamImp_genLegacyIndexXmlFile_success() {
+        val report =
+            compilationTestHelper.compileAll(
+                sourceFileNames = listOf("FakeNoArgImpl.KT", "FakeSchemas.KT")
+            )
+
+        compilationTestHelper.assertSuccessWithResourceContent(
+            report = report,
+            expectGeneratedResourceFileName = "app_functions.xml",
+            goldenFileName = "fakeNoArgImpl_app_function.xml"
+        )
+    }
 }
diff --git a/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/testings/CompilationTestHelper.kt b/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/testings/CompilationTestHelper.kt
index 4e6253d..cbb3c4b 100644
--- a/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/testings/CompilationTestHelper.kt
+++ b/appfunctions/appfunctions-compiler/src/test/java/androidx/appfunctions/compiler/testings/CompilationTestHelper.kt
@@ -17,6 +17,7 @@
 package androidx.appfunctions.compiler.testings
 
 import androidx.room.compiler.processing.util.DiagnosticMessage
+import androidx.room.compiler.processing.util.Resource
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.compiler.TestCompilationArguments
 import androidx.room.compiler.processing.util.compiler.TestCompilationResult
@@ -99,28 +100,20 @@
     }
 
     /**
-     * Asserts that the compilation succeeds and contains [expectGeneratedFileName] in generated
-     * sources that is identical to the content of [goldenFileName].
+     * Asserts that the compilation succeeds and contains [expectGeneratedSourceFileName] in
+     * generated sources that is identical to the content of [goldenFileName].
      */
-    fun assertSuccessWithContent(
+    fun assertSuccessWithSourceContent(
         report: CompilationReport,
-        expectGeneratedFileName: String,
+        expectGeneratedSourceFileName: String,
         goldenFileName: String,
     ) {
-        Truth.assertWithMessage(
-                """
-                Compile failed with error:
-                ${report.printDiagnostics(Diagnostic.Kind.ERROR)}
-            """
-                    .trimIndent()
-            )
-            .that(report.isSuccess)
-            .isTrue()
+        assertCompilationSuccess(report)
 
         val goldenFile = getGoldenFile(goldenFileName)
         val generatedSourceFile =
             report.generatedSourceFiles.single { sourceFile ->
-                sourceFile.source.relativePath.contains(expectGeneratedFileName)
+                sourceFile.source.relativePath.contains(expectGeneratedSourceFileName)
             }
         Truth.assertWithMessage(
                 """
@@ -136,6 +129,48 @@
             .isEqualTo(goldenFile.readText())
     }
 
+    /**
+     * Asserts that the compilation succeeds and contains [expectGeneratedResourceFileName] in
+     * generated resources that is identical to the content of [goldenFileName].
+     */
+    fun assertSuccessWithResourceContent(
+        report: CompilationReport,
+        expectGeneratedResourceFileName: String,
+        goldenFileName: String,
+    ) {
+        assertCompilationSuccess(report)
+
+        val goldenFile = getGoldenFile(goldenFileName)
+        val generatedResourceFile =
+            report.generatedResourceFiles.single { resourceFile ->
+                resourceFile.resource.relativePath.contains(expectGeneratedResourceFileName)
+            }
+        Truth.assertWithMessage(
+                """
+              Content of generated file [${generatedResourceFile.resource.relativePath}] does not match
+              the content of golden file [${goldenFile.path}].
+
+              To update the golden file,
+              run `cp ${generatedResourceFile.resourceFilePath} ${goldenFile.absolutePath}`
+            """
+                    .trimIndent()
+            )
+            .that(generatedResourceFile.resource.getContents())
+            .isEqualTo(goldenFile.readText())
+    }
+
+    private fun assertCompilationSuccess(report: CompilationReport) {
+        Truth.assertWithMessage(
+                """
+                    Compile failed with error:
+                    ${report.printDiagnostics(Diagnostic.Kind.ERROR)}
+                """
+                    .trimIndent()
+            )
+            .that(report.isSuccess)
+            .isTrue()
+    }
+
     fun assertErrorWithMessage(report: CompilationReport, expectedErrorMessage: String) {
         Truth.assertWithMessage("Compile succeed").that(report.isSuccess).isFalse()
 
@@ -196,6 +231,8 @@
         val generatedSourceFiles: List<GeneratedSourceFile>,
         /** A map of diagnostics results. */
         val diagnostics: Map<Diagnostic.Kind, List<DiagnosticMessage>>,
+        /** A list of generated source files. */
+        val generatedResourceFiles: List<GeneratedResourceFile>,
     ) {
         /** Print the diagnostics result of type [kind]. */
         fun printDiagnostics(kind: Diagnostic.Kind): String {
@@ -216,7 +253,11 @@
                         result.generatedSources.map { source ->
                             GeneratedSourceFile.create(source, outputDir)
                         },
-                    diagnostics = result.diagnostics
+                    diagnostics = result.diagnostics,
+                    generatedResourceFiles =
+                        result.generatedResources.map { resource ->
+                            GeneratedResourceFile.create(resource, outputDir)
+                        }
                 )
             }
         }
@@ -236,4 +277,22 @@
             }
         }
     }
+
+    /** A wrapper class contains [Resource] with its file path. */
+    data class GeneratedResourceFile(val resource: Resource, val resourceFilePath: Path) {
+        companion object {
+            internal fun create(resource: Resource, outputDir: Path): GeneratedResourceFile {
+                val filePath =
+                    outputDir.resolve(resource.relativePath).apply {
+                        parent?.createDirectories()
+                        createFile()
+                        writeText(resource.getContents())
+                    }
+                return GeneratedResourceFile(resource, filePath)
+            }
+        }
+    }
 }
+
+private fun Resource.getContents(): String =
+    openInputStream().bufferedReader().use { it.readText() }
diff --git a/appfunctions/appfunctions-compiler/src/test/test-data/input/AllPrimitiveInputFunctions.KT b/appfunctions/appfunctions-compiler/src/test/test-data/input/AllPrimitiveInputFunctions.KT
new file mode 100644
index 0000000..c1fda4a
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/test/test-data/input/AllPrimitiveInputFunctions.KT
@@ -0,0 +1,55 @@
+package com.testdata
+
+import androidx.appfunctions.AppFunction
+import androidx.appfunctions.AppFunctionContext
+
+class AllPrimitiveInputFunctions {
+    @AppFunction fun simpleFunctionInt(appFunctionContext: AppFunctionContext, intParam: Int) {}
+
+    @AppFunction fun simpleFunctionLong(appFunctionContext: AppFunctionContext, longParam: Long) {}
+
+    @AppFunction
+    fun simpleFunctionFloat(appFunctionContext: AppFunctionContext, floatParam: Float) {}
+
+    @AppFunction
+    fun simpleFunctionDouble(appFunctionContext: AppFunctionContext, doubleParam: Double) {}
+
+    @AppFunction
+    fun simpleFunctionBoolean(appFunctionContext: AppFunctionContext, booleanParam: Boolean) {}
+
+    @AppFunction
+    fun simpleFunctionString(appFunctionContext: AppFunctionContext, stringParam: String) {}
+
+    @AppFunction
+    fun simpleFunctionIntArray(appFunctionContext: AppFunctionContext, intArrayParam: IntArray) {}
+
+    @AppFunction
+    fun simpleFunctionLongArray(
+        appFunctionContext: AppFunctionContext,
+        longArrayParam: LongArray
+    ) {}
+
+    @AppFunction
+    fun simpleFunctionFloatArray(
+        appFunctionContext: AppFunctionContext,
+        floatArrayParam: FloatArray
+    ) {}
+
+    @AppFunction
+    fun simpleFunctionDoubleArray(
+        appFunctionContext: AppFunctionContext,
+        doubleArrayParam: DoubleArray
+    ) {}
+
+    @AppFunction
+    fun simpleFunctionBooleanArray(
+        appFunctionContext: AppFunctionContext,
+        booleanArrayParam: BooleanArray
+    ) {}
+
+    @AppFunction
+    fun simpleFunctionByteArray(
+        appFunctionContext: AppFunctionContext,
+        byteArrayParam: ByteArray
+    ) {}
+}
diff --git a/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeNoArgImpl.KT b/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeNoArgImpl.KT
new file mode 100644
index 0000000..4b09194
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeNoArgImpl.KT
@@ -0,0 +1,8 @@
+package com.testdata
+
+import androidx.appfunctions.AppFunction
+import androidx.appfunctions.AppFunctionContext
+
+class FakeNoArgImpl : FakeNoArg {
+    @AppFunction override fun noArg(appFunctionContext: AppFunctionContext) {}
+}
diff --git a/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeSchemas.KT b/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeSchemas.KT
new file mode 100644
index 0000000..a59c737
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/test/test-data/input/FakeSchemas.KT
@@ -0,0 +1,11 @@
+package com.testdata
+
+import androidx.appfunctions.AppFunctionContext
+import androidx.appfunctions.AppFunctionSchemaDefinition
+
+private const val FAKE_CATEGORY = "fake_schema_category"
+
+@AppFunctionSchemaDefinition(name = "noArg", version = 1, category = FAKE_CATEGORY)
+interface FakeNoArg {
+    fun noArg(appFunctionContext: AppFunctionContext)
+}
diff --git a/appfunctions/appfunctions-compiler/src/test/test-data/output/$AllPrimitiveInputFunctions_AppFunctionInventory_Impl.KT b/appfunctions/appfunctions-compiler/src/test/test-data/output/$AllPrimitiveInputFunctions_AppFunctionInventory_Impl.KT
new file mode 100644
index 0000000..dd650f0
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/test/test-data/output/$AllPrimitiveInputFunctions_AppFunctionInventory_Impl.KT
@@ -0,0 +1,12 @@
+package com.testdata
+
+import androidx.appfunctions.`internal`.AppFunctionInventory
+import androidx.appfunctions.metadata.AppFunctionMetadata
+import javax.`annotation`.processing.Generated
+import kotlin.String
+import kotlin.collections.Map
+
+@Generated("androidx.appfunctions.compiler.AppFunctionCompiler")
+public class `$AllPrimitiveInputFunctions_AppFunctionInventory_Impl` : AppFunctionInventory {
+  override val functionIdToMetadataMap: Map<String, AppFunctionMetadata> = mapOf()
+}
diff --git a/appfunctions/appfunctions-compiler/src/test/test-data/output/fakeNoArgImpl_app_function.xml b/appfunctions/appfunctions-compiler/src/test/test-data/output/fakeNoArgImpl_app_function.xml
new file mode 100644
index 0000000..229bae7
--- /dev/null
+++ b/appfunctions/appfunctions-compiler/src/test/test-data/output/fakeNoArgImpl_app_function.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<appfunctions>
+    <appfunction>
+        <function_id>com.testdata.FakeNoArgImpl#noArg</function_id>
+        <schema_category>fake_schema_category</schema_category>
+        <schema_name>noArg</schema_name>
+        <schema_version>1</schema_version>
+        <enabled_by_default>true</enabled_by_default>
+    </appfunction>
+</appfunctions>
diff --git a/appfunctions/appfunctions-runtime/api/current.txt b/appfunctions/appfunctions-runtime/api/current.txt
index 7394582..0c2d890 100644
--- a/appfunctions/appfunctions-runtime/api/current.txt
+++ b/appfunctions/appfunctions-runtime/api/current.txt
@@ -6,5 +6,25 @@
     property public abstract boolean isEnabled;
   }
 
+  public final class AppFunctionConfiguration {
+    method public java.util.Map<java.lang.Class<? extends java.lang.Object?>,androidx.appfunctions.AppFunctionFactory<? extends java.lang.Object?>> getFactories();
+    property public final java.util.Map<java.lang.Class<? extends java.lang.Object?>,androidx.appfunctions.AppFunctionFactory<? extends java.lang.Object?>> factories;
+  }
+
+  public static final class AppFunctionConfiguration.Builder {
+    ctor public AppFunctionConfiguration.Builder();
+    method public <T> androidx.appfunctions.AppFunctionConfiguration.Builder addFactory(Class<T> enclosingClass, androidx.appfunctions.AppFunctionFactory<T> factory);
+    method public androidx.appfunctions.AppFunctionConfiguration build();
+  }
+
+  public static interface AppFunctionConfiguration.Provider {
+    method public androidx.appfunctions.AppFunctionConfiguration getAppFunctionConfiguration();
+    property public abstract androidx.appfunctions.AppFunctionConfiguration appFunctionConfiguration;
+  }
+
+  public interface AppFunctionFactory<T> {
+    method public T createEnclosingClass(Class<T> enclosingClass);
+  }
+
 }
 
diff --git a/appfunctions/appfunctions-runtime/api/restricted_current.txt b/appfunctions/appfunctions-runtime/api/restricted_current.txt
index 7394582..0c2d890 100644
--- a/appfunctions/appfunctions-runtime/api/restricted_current.txt
+++ b/appfunctions/appfunctions-runtime/api/restricted_current.txt
@@ -6,5 +6,25 @@
     property public abstract boolean isEnabled;
   }
 
+  public final class AppFunctionConfiguration {
+    method public java.util.Map<java.lang.Class<? extends java.lang.Object?>,androidx.appfunctions.AppFunctionFactory<? extends java.lang.Object?>> getFactories();
+    property public final java.util.Map<java.lang.Class<? extends java.lang.Object?>,androidx.appfunctions.AppFunctionFactory<? extends java.lang.Object?>> factories;
+  }
+
+  public static final class AppFunctionConfiguration.Builder {
+    ctor public AppFunctionConfiguration.Builder();
+    method public <T> androidx.appfunctions.AppFunctionConfiguration.Builder addFactory(Class<T> enclosingClass, androidx.appfunctions.AppFunctionFactory<T> factory);
+    method public androidx.appfunctions.AppFunctionConfiguration build();
+  }
+
+  public static interface AppFunctionConfiguration.Provider {
+    method public androidx.appfunctions.AppFunctionConfiguration getAppFunctionConfiguration();
+    property public abstract androidx.appfunctions.AppFunctionConfiguration appFunctionConfiguration;
+  }
+
+  public interface AppFunctionFactory<T> {
+    method public T createEnclosingClass(Class<T> enclosingClass);
+  }
+
 }
 
diff --git a/appfunctions/appfunctions-runtime/build.gradle b/appfunctions/appfunctions-runtime/build.gradle
index 146190f..63e97bb 100644
--- a/appfunctions/appfunctions-runtime/build.gradle
+++ b/appfunctions/appfunctions-runtime/build.gradle
@@ -39,6 +39,7 @@
     // Test dependencies
     testImplementation(libs.junit)
     testImplementation(libs.truth)
+    testImplementation(libs.mockitoCore4)
 
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testRules)
diff --git a/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionConfiguration.kt b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionConfiguration.kt
new file mode 100644
index 0000000..3a8f5ad
--- /dev/null
+++ b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionConfiguration.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions
+
+/** The configuration object used to customize AppFunction setup. */
+public class AppFunctionConfiguration
+internal constructor(
+    /**
+     * A map of [AppFunctionFactory] used to construct the enclosing classes of AppFunctions.
+     *
+     * The keys in this map are the enclosing classes of the AppFunctions to be constructed, and the
+     * values are the corresponding [AppFunctionFactory] instance. If not provided in the map, the
+     * default no-argument constructors will be used to construct the classes.
+     */
+    public val factories: Map<Class<*>, AppFunctionFactory<*>>
+) {
+    /**
+     * A class to provide customized [AppFunctionConfiguration] object.
+     *
+     * To provide the configuration, implements the [AppFunctionConfiguration.Provider] interface on
+     * your [android.app.Application] class.
+     */
+    public interface Provider {
+        /** The [AppFunctionConfiguration] used to customize AppFunction setup. */
+        public val appFunctionConfiguration: AppFunctionConfiguration
+    }
+
+    /** A builder for [AppFunctionConfiguration]. */
+    public class Builder {
+
+        private val factories = mutableMapOf<Class<*>, AppFunctionFactory<*>>()
+
+        /**
+         * Adds a [factory] instance for creating an [enclosingClass].
+         *
+         * If there is already a factory instance set for [enclosingClass], it will be overridden.
+         */
+        public fun <T : Any> addFactory(
+            enclosingClass: Class<T>,
+            factory: AppFunctionFactory<T>
+        ): Builder {
+            factories[enclosingClass] = factory
+            return this
+        }
+
+        /** Builds the [AppFunctionConfiguration]. */
+        public fun build(): AppFunctionConfiguration {
+            return AppFunctionConfiguration(factories.toMap())
+        }
+    }
+}
diff --git a/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionFactory.kt b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionFactory.kt
new file mode 100644
index 0000000..5e256da
--- /dev/null
+++ b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/AppFunctionFactory.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions
+
+/**
+ * A factory for instantiate the enclosing class of AppFunctions. The factory is invoked every time
+ * a function call to one of the AppFunction within the class is made.
+ *
+ * Implement a custom [AppFunctionFactory] if your AppFunction's enclosing class require constructor
+ * parameter or custom instantiation logic beyond the default no-argument constructor. This allows
+ * you to inject dependencies or handle more complex object creation scenarios.
+ *
+ * @param T The specific type of AppFunction class this factory creates.
+ */
+public interface AppFunctionFactory<T : Any> {
+    /**
+     * Overrides this method to provide your custom creation logic for enclosing class of
+     * AppFunctions.
+     */
+    public fun createEnclosingClass(enclosingClass: Class<T>): T
+}
diff --git a/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactory.kt b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactory.kt
new file mode 100644
index 0000000..ddc760b
--- /dev/null
+++ b/appfunctions/appfunctions-runtime/src/main/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactory.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions.internal
+
+import android.content.Context
+import android.util.Log
+import androidx.annotation.RestrictTo
+import androidx.appfunctions.AppFunctionConfiguration
+import androidx.appfunctions.AppFunctionFactory
+import androidx.appfunctions.internal.Constants.APP_FUNCTIONS_TAG
+import java.lang.reflect.InvocationTargetException
+
+/**
+ * An [AppFunctionFactory] implementation that will incorporate [AppFunctionConfiguration] from
+ * [context] to create AppFunction enclosing classes.
+ *
+ * If the application context from [context] overrides [AppFunctionConfiguration.Provider], the
+ * customize [AppFunctionFactory] will be used to instantiate the enclosing class. Otherwise, it
+ * will use reflection to create the instance assuming the enclosing class has no argument
+ * constructor.
+ *
+ * [createEnclosingClass] will throw [AppFunctionInstantiationException] if unable to instantiate
+ * the enclosing class.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class ConfigurableAppFunctionFactory<T : Any>(
+    private val context: Context,
+) : AppFunctionFactory<T> {
+
+    override fun createEnclosingClass(enclosingClass: Class<T>): T {
+        val configurationProvider = context.applicationContext as? AppFunctionConfiguration.Provider
+        val customFactory =
+            configurationProvider?.appFunctionConfiguration?.factories?.get(enclosingClass)
+        if (customFactory == null) {
+            Log.d(APP_FUNCTIONS_TAG, "Unable to find custom factory for [$enclosingClass]")
+            return getNoArgumentAppFunctionFactory<T>().createEnclosingClass(enclosingClass)
+        }
+
+        @Suppress("UNCHECKED_CAST")
+        return (customFactory as AppFunctionFactory<T>).createEnclosingClass(enclosingClass)
+    }
+
+    /** Thrown when unable to instantiate the AppFunction enclosing class. */
+    public class AppFunctionInstantiationException(errorMessage: String) :
+        RuntimeException(errorMessage)
+
+    private fun <T : Any> getNoArgumentAppFunctionFactory(): AppFunctionFactory<T> {
+        return object : AppFunctionFactory<T> {
+            override fun createEnclosingClass(enclosingClass: Class<T>): T {
+                return try {
+                    enclosingClass.getDeclaredConstructor().newInstance()
+                } catch (_: IllegalAccessException) {
+                    throw AppFunctionInstantiationException(
+                        "Cannot access the constructor of $enclosingClass"
+                    )
+                } catch (_: NoSuchMethodException) {
+                    throw AppFunctionInstantiationException(
+                        "$enclosingClass requires additional parameter to create. " +
+                            "Please either remove the additional parameters or implement the " +
+                            "${AppFunctionFactory::class.qualifiedName} and provide it in " +
+                            "${AppFunctionConfiguration::class.qualifiedName}",
+                    )
+                } catch (_: InstantiationException) {
+                    throw AppFunctionInstantiationException(
+                        "$enclosingClass should have a public no-argument constructor"
+                    )
+                } catch (_: InvocationTargetException) {
+                    throw AppFunctionInstantiationException(
+                        "Something went wrong when creating $enclosingClass"
+                    )
+                } catch (_: ExceptionInInitializerError) {
+                    throw AppFunctionInstantiationException(
+                        "Something went wrong when creating $enclosingClass"
+                    )
+                }
+            }
+        }
+    }
+}
diff --git a/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/AppFunctionConfigurationTest.kt b/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/AppFunctionConfigurationTest.kt
new file mode 100644
index 0000000..c192af9
--- /dev/null
+++ b/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/AppFunctionConfigurationTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class AppFunctionConfigurationTest {
+    @Test
+    fun testEmpty() {
+        val configuration = AppFunctionConfiguration.Builder().build()
+
+        assertThat(configuration.factories).isEmpty()
+    }
+
+    @Test
+    fun testUniqueFactories() {
+        val factory1 = TestAppFunctionClass1.Factory()
+        val factory2 = TestAppFunctionClass2.Factory()
+
+        val configuration =
+            AppFunctionConfiguration.Builder()
+                .addFactory(TestAppFunctionClass1::class.java, factory1)
+                .addFactory(TestAppFunctionClass2::class.java, factory2)
+                .build()
+
+        assertThat(configuration.factories).hasSize(2)
+        assertThat(configuration.factories[TestAppFunctionClass1::class.java]).isEqualTo(factory1)
+        assertThat(configuration.factories[TestAppFunctionClass2::class.java]).isEqualTo(factory2)
+    }
+
+    @Test
+    fun testDuplicatedFactories() {
+        val factory1 = TestAppFunctionClass1.Factory()
+
+        val configuration =
+            AppFunctionConfiguration.Builder()
+                .addFactory(TestAppFunctionClass1::class.java, factory1)
+                .addFactory(TestAppFunctionClass1::class.java, factory1)
+                .build()
+
+        assertThat(configuration.factories).hasSize(1)
+        assertThat(configuration.factories[TestAppFunctionClass1::class.java]).isEqualTo(factory1)
+    }
+
+    internal class TestAppFunctionClass1 {
+        internal class Factory : AppFunctionFactory<TestAppFunctionClass1> {
+            override fun createEnclosingClass(
+                enclosingClass: Class<TestAppFunctionClass1>
+            ): TestAppFunctionClass1 {
+                return TestAppFunctionClass1()
+            }
+        }
+    }
+
+    internal class TestAppFunctionClass2 {
+        internal class Factory : AppFunctionFactory<TestAppFunctionClass2> {
+            override fun createEnclosingClass(
+                enclosingClass: Class<TestAppFunctionClass2>
+            ): TestAppFunctionClass2 {
+                return TestAppFunctionClass2()
+            }
+        }
+    }
+}
diff --git a/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactoryTest.kt b/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactoryTest.kt
new file mode 100644
index 0000000..3983d25
--- /dev/null
+++ b/appfunctions/appfunctions-runtime/src/test/java/androidx/appfunctions/internal/ConfigurableAppFunctionFactoryTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.appfunctions.internal
+
+import android.content.Context
+import android.content.ContextWrapper
+import androidx.appfunctions.AppFunctionConfiguration
+import androidx.appfunctions.AppFunctionFactory
+import androidx.appfunctions.internal.ConfigurableAppFunctionFactory.AppFunctionInstantiationException
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.mock
+
+class ConfigurableAppFunctionFactoryTest {
+
+    private lateinit var noConfigContext: Context
+
+    private lateinit var configContext: Context
+
+    @Before
+    fun setup() {
+        noConfigContext = FakeNoConfigContext(mock(Context::class.java))
+        configContext = FakeConfigProviderContext(mock(Context::class.java))
+    }
+
+    @Test
+    fun testCreateNoArgEnclosingClass_withoutConfig() {
+        val factory = ConfigurableAppFunctionFactory<NoArgEnclosingClass>(noConfigContext)
+        factory.createEnclosingClass(NoArgEnclosingClass::class.java)
+    }
+
+    @Test
+    fun testCreateNoArgEnclosingClass_withConfig() {
+        val creator = ConfigurableAppFunctionFactory<NoArgEnclosingClass>(configContext)
+        creator.createEnclosingClass(NoArgEnclosingClass::class.java)
+    }
+
+    @Test
+    fun testCreateNoArgEnclosingClass_ifProvideFactory() {
+        val creator = ConfigurableAppFunctionFactory<NoArgWithFactoryEnclosingClass>(configContext)
+        creator.createEnclosingClass(NoArgWithFactoryEnclosingClass::class.java)
+    }
+
+    @Test
+    fun testCreateEnclosingClassRequiredArgs_withoutFactory() {
+        val creator = ConfigurableAppFunctionFactory<RequiredArgsEnclosingClass>(noConfigContext)
+        assertThrows(AppFunctionInstantiationException::class.java) {
+            creator.createEnclosingClass(RequiredArgsEnclosingClass::class.java)
+        }
+    }
+
+    @Test
+    fun testCreateEnclosingClassRequiredArgs_withFactory() {
+        val creator = ConfigurableAppFunctionFactory<RequiredArgsEnclosingClass>(configContext)
+        creator.createEnclosingClass(RequiredArgsEnclosingClass::class.java)
+    }
+
+    @Test
+    fun testCreateEnclosingClassWithPrivateConstructor() {
+        val creator =
+            ConfigurableAppFunctionFactory<PrivateConstructorEnclosingClass>(noConfigContext)
+        assertThrows(AppFunctionInstantiationException::class.java) {
+            creator.createEnclosingClass(PrivateConstructorEnclosingClass::class.java)
+        }
+    }
+
+    @Test
+    fun testCreateEnclosingClass_thatThrowErrorDuringInvocation() {
+        val creator = ConfigurableAppFunctionFactory<InvocationErrorEnclosingClass>(noConfigContext)
+        assertThrows(AppFunctionInstantiationException::class.java) {
+            creator.createEnclosingClass(InvocationErrorEnclosingClass::class.java)
+        }
+    }
+
+    @Test
+    fun testCreateEnclosingClass_thatThrowErrorDuringInitialization() {
+        val creator = ConfigurableAppFunctionFactory<InitializeErrorEnclosingClass>(noConfigContext)
+        assertThrows(AppFunctionInstantiationException::class.java) {
+            creator.createEnclosingClass(InitializeErrorEnclosingClass::class.java)
+        }
+    }
+
+    // Fake context
+    class FakeConfigProviderContext(baseContext: Context) :
+        ContextWrapper(baseContext), AppFunctionConfiguration.Provider {
+        override fun getApplicationContext(): Context? = this
+
+        override val appFunctionConfiguration: AppFunctionConfiguration
+            get() =
+                AppFunctionConfiguration.Builder()
+                    .addFactory(
+                        NoArgWithFactoryEnclosingClass::class.java,
+                        NoArgWithFactoryEnclosingClass.Factory()
+                    )
+                    .addFactory(
+                        RequiredArgsEnclosingClass::class.java,
+                        RequiredArgsEnclosingClass.Factory()
+                    )
+                    .build()
+    }
+
+    class FakeNoConfigContext(baseContext: Context) : ContextWrapper(baseContext) {
+        override fun getApplicationContext(): Context? = this
+    }
+
+    // Test enclosing classes
+    class NoArgEnclosingClass()
+
+    class NoArgWithFactoryEnclosingClass() {
+        class Factory : AppFunctionFactory<NoArgWithFactoryEnclosingClass> {
+            override fun createEnclosingClass(
+                enclosingClass: Class<NoArgWithFactoryEnclosingClass>
+            ): NoArgWithFactoryEnclosingClass {
+                return NoArgWithFactoryEnclosingClass()
+            }
+        }
+    }
+
+    class RequiredArgsEnclosingClass(val x: Int) {
+        class Factory : AppFunctionFactory<RequiredArgsEnclosingClass> {
+            override fun createEnclosingClass(
+                enclosingClass: Class<RequiredArgsEnclosingClass>
+            ): RequiredArgsEnclosingClass {
+                return RequiredArgsEnclosingClass(0)
+            }
+        }
+    }
+
+    class PrivateConstructorEnclosingClass private constructor()
+
+    class InvocationErrorEnclosingClass private constructor(val x: Int) {
+        constructor() : this(0) {
+            throw RuntimeException()
+        }
+    }
+
+    class InitializeErrorEnclosingClass() {
+        init {
+            throw RuntimeException()
+        }
+    }
+}
diff --git a/benchmark/benchmark-common/api/current.txt b/benchmark/benchmark-common/api/current.txt
index 44c9777..6dea054 100644
--- a/benchmark/benchmark-common/api/current.txt
+++ b/benchmark/benchmark-common/api/current.txt
@@ -54,6 +54,11 @@
 
   @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
     ctor public MicrobenchmarkConfig();
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount);
     ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount, optional Integer? measurementCount);
     method public Integer? getMeasurementCount();
     method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
diff --git a/benchmark/benchmark-common/api/restricted_current.txt b/benchmark/benchmark-common/api/restricted_current.txt
index f25ea8e..c94bb5b 100644
--- a/benchmark/benchmark-common/api/restricted_current.txt
+++ b/benchmark/benchmark-common/api/restricted_current.txt
@@ -57,6 +57,11 @@
 
   @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
     ctor public MicrobenchmarkConfig();
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler);
+    ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount);
     ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean traceAppTagEnabled, optional boolean perfettoSdkTracingEnabled, optional androidx.benchmark.ProfilerConfig? profiler, optional Integer? warmupCount, optional Integer? measurementCount);
     method public Integer? getMeasurementCount();
     method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
index 456635c..61d9775 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/DeviceInfoTest.kt
@@ -62,6 +62,26 @@
     }
 
     @Test
+    fun willMethodTracingAffectMeasurements() {
+        // first clause - 26 through 30 (inclusive) affected
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(25, -1))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(26, -1L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(30, -1L))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(31, 310000000L))
+
+        // second clause - art API 34 regression
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 330000000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(33, 340000000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(33, 341513000L - 1))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 341513000L))
+
+        // third clause - art API 34 regression and internal build ID
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(33, 990090000L))
+        assertTrue(DeviceInfo.willMethodTracingAffectMeasurements(34, 990090000L))
+        assertFalse(DeviceInfo.willMethodTracingAffectMeasurements(35, 990090000L))
+    }
+
+    @Test
     fun artMainlineVersion() =
         validateArtMainlineVersion(artMainlineVersion = DeviceInfo.artMainlineVersion)
 }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
index 3083747..002ab09 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
@@ -302,6 +302,16 @@
     private const val ART_MAINLINE_MIN_VERSION_VERIFY_CLEARS_RUNTIME_IMAGE = 350800000L
 
     /**
+     * ART mainline 990090000 means the module is built from source in the system image and isn't
+     * updatable, and thus expectations should be conservative - assume that any potential bug on
+     * the current SDK version may be present on this device.
+     *
+     * Ideally, we'd have a minimum release build ID, but these may not be consistently and easily
+     * sortable.
+     */
+    private const val ART_MAINLINE_INTERNAL_BUILD_MIN = 990000000
+
+    /**
      * Used when mainline version failed to detect, but this is accepted due to low API level (<34)
      * where presence isn't guaranteed (e.g. go devices)
      */
@@ -320,15 +330,18 @@
             else -> ART_MAINLINE_VERSION_UNDETECTED
         }
 
-    val methodTracingAffectsMeasurements =
-        Build.VERSION.SDK_INT in 26..30 || // b/313868903
-            artMainlineVersion in ART_MAINLINE_VERSIONS_AFFECTING_METHOD_TRACING // b/303660864
+    fun willMethodTracingAffectMeasurements(sdkInt: Int, artVersion: Long): Boolean =
+        sdkInt in 26..30 || // b/313868903
+            artVersion in ART_MAINLINE_VERSIONS_AFFECTING_METHOD_TRACING || // b/303660864
+            (sdkInt == 34 && artVersion >= ART_MAINLINE_INTERNAL_BUILD_MIN) // b/303686344#comment31
 
-    fun isClassLoadTracingAvailable(targetApiLevel: Int, targetArtMainlineVersion: Long?): Boolean =
-        targetApiLevel >= 35 ||
-            (targetApiLevel >= 31 &&
-                (targetArtMainlineVersion == null ||
-                    targetArtMainlineVersion >= ART_MAINLINE_MIN_VERSION_CLASS_LOAD_TRACING))
+    val methodTracingAffectsMeasurements =
+        willMethodTracingAffectMeasurements(Build.VERSION.SDK_INT, artMainlineVersion)
+
+    fun isClassLoadTracingAvailable(sdkInt: Int, artVersion: Long?): Boolean =
+        sdkInt >= 35 ||
+            (sdkInt >= 31 &&
+                (artVersion == null || artVersion >= ART_MAINLINE_MIN_VERSION_CLASS_LOAD_TRACING))
 
     val supportsClassLoadTracing =
         isClassLoadTracingAvailable(Build.VERSION.SDK_INT, artMainlineVersion)
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
index 102de5e..d2dd087 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkConfig.kt
@@ -23,6 +23,7 @@
  */
 @ExperimentalBenchmarkConfigApi
 class MicrobenchmarkConfig
+@JvmOverloads
 constructor(
     /**
      * Timing metrics for primary phase, post-warmup
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index 4810691..aaa9668 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -23,9 +23,7 @@
 import androidx.benchmark.Shell
 import androidx.benchmark.macro.BatteryCharge.hasMinimumCharge
 import androidx.benchmark.macro.PowerMetric.Companion.deviceSupportsHighPrecisionTracking
-import androidx.benchmark.macro.PowerMetric.Type
 import androidx.benchmark.macro.PowerRail.hasMetrics
-import androidx.benchmark.macro.TraceSectionMetric.Mode
 import androidx.benchmark.macro.perfetto.BatteryDischargeQuery
 import androidx.benchmark.macro.perfetto.FrameTimingQuery
 import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric
@@ -730,8 +728,8 @@
                 .asMeasurements("artVerifyClass") +
             if (
                 DeviceInfo.isClassLoadTracingAvailable(
-                    targetApiLevel = captureInfo.apiLevel,
-                    targetArtMainlineVersion = captureInfo.artMainlineVersion
+                    sdkInt = captureInfo.apiLevel,
+                    artVersion = captureInfo.artMainlineVersion
                 )
             ) {
                 traceSession
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
index 885e0de..3ed68f0 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/GenerateApiTask.kt
@@ -18,7 +18,6 @@
 
 import androidx.build.Version
 import androidx.build.checkapi.ApiLocation
-import androidx.build.checkapi.StandardCompilationInputs
 import java.io.File
 import javax.inject.Inject
 import org.gradle.api.file.Directory
@@ -79,13 +78,6 @@
             check(compiled.exists()) { "File " + compiled + " does not exist" }
         }
 
-        val inputs =
-            StandardCompilationInputs(
-                sourcePaths = sourcePaths,
-                dependencyClasspath = dependencyClasspath,
-                bootClasspath = bootClasspath
-            )
-
         val levelsArgs =
             getGenerateApiLevelsArgs(
                 getPastApiFiles(),
@@ -96,7 +88,7 @@
         generateApi(
             metalavaClasspath,
             createProjectXmlFile(),
-            inputs,
+            sourcePaths.files,
             apiLocation.get(),
             ApiLintMode.CheckBaseline(baselines.get().apiLintFile, targetsJavaConsumers.get()),
             generateRestrictToLibraryGroupAPIs,
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
index 580c652..f445c79 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
@@ -18,7 +18,6 @@
 
 import androidx.build.Version
 import androidx.build.checkapi.ApiLocation
-import androidx.build.checkapi.CompilationInputs
 import androidx.build.getLibraryByName
 import androidx.build.logging.TERMINAL_RED
 import androidx.build.logging.TERMINAL_RESET
@@ -187,6 +186,12 @@
                 )
                 .joinToString()
         )
+    // Acronyms that can be used in their all-caps form. "SQ" is included to allow "SQLite".
+    val allowedAcronyms = listOf("SQL", "SQ", "URL", "EGL", "GL", "KHR")
+    for (acronym in allowedAcronyms) {
+        args.add("--api-lint-allowed-acronym")
+        args.add(acronym)
+    }
     val javaOnlyIssues = listOf("MissingJvmstatic", "ArrayReturn", "ValueClassDefinition")
     val javaOnlyErrorLevel =
         if (targetsJavaConsumers) {
@@ -243,8 +248,8 @@
  */
 internal fun generateApi(
     metalavaClasspath: FileCollection,
-    projectXml: File?,
-    files: CompilationInputs,
+    projectXml: File,
+    sourcePaths: Collection<File>,
     apiLocation: ApiLocation,
     apiLintMode: ApiLintMode,
     includeRestrictToLibraryGroupApis: Boolean,
@@ -268,7 +273,7 @@
         generateApi(
             metalavaClasspath,
             projectXml,
-            files,
+            sourcePaths,
             apiLocation,
             generateApiMode,
             apiLintMode,
@@ -287,8 +292,8 @@
  */
 private fun generateApi(
     metalavaClasspath: FileCollection,
-    projectXml: File?,
-    files: CompilationInputs,
+    projectXml: File,
+    sourcePaths: Collection<File>,
     outputLocation: ApiLocation,
     generateApiMode: GenerateApiMode,
     apiLintMode: ApiLintMode,
@@ -300,10 +305,8 @@
 ) {
     val args =
         getGenerateApiArgs(
-            files.bootClasspath,
-            files.dependencyClasspath,
             projectXml,
-            files.sourcePaths.files,
+            sourcePaths,
             outputLocation,
             generateApiMode,
             apiLintMode,
@@ -318,9 +321,7 @@
  * [GenerateApiMode.PublicApi].
  */
 fun getGenerateApiArgs(
-    bootClasspath: FileCollection,
-    dependencyClasspath: FileCollection,
-    projectXml: File?,
+    projectXml: File,
     sourcePaths: Collection<File>,
     outputLocation: ApiLocation?,
     generateApiMode: GenerateApiMode,
@@ -333,19 +334,10 @@
         mutableListOf(
             "--source-path",
             sourcePaths.filter { it.exists() }.joinToString(File.pathSeparator),
+            "--project",
+            projectXml.path
         )
 
-    // If there's a project xml file, the classpath isn't needed
-    args +=
-        if (projectXml != null) {
-            listOf("--project", projectXml.path)
-        } else {
-            listOf(
-                "--classpath",
-                (bootClasspath.files + dependencyClasspath.files).joinToString(File.pathSeparator)
-            )
-        }
-
     args += listOf("--format=v4", "--warnings-as-errors")
 
     pathToManifest?.let { args += listOf("--manifest", pathToManifest) }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
index cda75c7..a84b92e 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTask.kt
@@ -110,21 +110,22 @@
     @get:Input abstract val targetsJavaConsumers: Property<Boolean>
 
     /**
-     * Information about all source sets for multiplatform projects. Non-multiplatform projects can
-     * be represented as a list with one source set.
+     * Information about all source sets for multiplatform projects. Non-multiplatform projects
+     * should be represented as a list with one source set.
      *
      * This is marked as [Internal] because [compiledSources] is what should determine whether to
      * rerun metalava.
      */
-    @get:Internal abstract val optionalSourceSets: ListProperty<SourceSetInputs>
+    @get:Internal abstract val sourceSets: ListProperty<SourceSetInputs>
 
     /**
-     * Creates an XML file representing the project structure, if [optionalSourceSets] was set.
+     * Creates an XML file representing the project structure.
      *
      * This should only be called during task execution.
      */
-    protected fun createProjectXmlFile(): File? {
-        val sourceSets = optionalSourceSets.get().ifEmpty { null } ?: return null
+    protected fun createProjectXmlFile(): File {
+        val sourceSets = sourceSets.get()
+        check(sourceSets.isNotEmpty()) { "Project must have at least one source set." }
         val outputFile = File(temporaryDir, "project.xml")
         ProjectXml.create(
             sourceSets,
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
index e5e949a..f0cea08 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaTasks.kt
@@ -24,6 +24,7 @@
 import androidx.build.checkapi.ApiLocation
 import androidx.build.checkapi.CompilationInputs
 import androidx.build.checkapi.MultiplatformCompilationInputs
+import androidx.build.checkapi.SourceSetInputs
 import androidx.build.checkapi.getRequiredCompatibilityApiLocation
 import androidx.build.uptodatedness.cacheEvenIfNoOutputs
 import androidx.build.version
@@ -218,7 +219,19 @@
         task.bootClasspath = inputs.bootClasspath
         androidManifest?.let { task.manifestPath.set(it) }
         if (inputs is MultiplatformCompilationInputs) {
-            task.optionalSourceSets.set(inputs.sourceSets)
+            task.sourceSets.set(inputs.sourceSets)
+        } else {
+            // Represent a non-multiplatform project as one source set.
+            task.sourceSets.set(
+                listOf(
+                    SourceSetInputs(
+                        sourceSetName = "main",
+                        dependsOnSourceSets = emptyList(),
+                        sourcePaths = inputs.sourcePaths,
+                        dependencyClasspath = inputs.dependencyClasspath
+                    )
+                )
+            )
         }
     }
 }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
index 351b606..617dc43 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/RegenerateOldApisTask.kt
@@ -18,8 +18,7 @@
 
 import androidx.build.Version
 import androidx.build.checkapi.ApiLocation
-import androidx.build.checkapi.CompilationInputs
-import androidx.build.checkapi.StandardCompilationInputs
+import androidx.build.checkapi.SourceSetInputs
 import androidx.build.checkapi.getApiFileVersion
 import androidx.build.checkapi.getRequiredCompatibilityApiLocation
 import androidx.build.checkapi.getVersionedApiLocation
@@ -160,20 +159,27 @@
         outputApiLocation: ApiLocation,
     ) {
         val mavenId = "$groupId:$artifactId:$version"
-        val inputs: CompilationInputs?
-        try {
-            inputs = getFiles(runnerProject, mavenId)
-        } catch (e: TypedResolveException) {
-            runnerProject.logger.info("Ignoring missing artifact $mavenId: $e")
-            return
-        }
+        val (compiledSources, sourceSets) =
+            try {
+                getFiles(runnerProject, mavenId)
+            } catch (e: TypedResolveException) {
+                runnerProject.logger.info("Ignoring missing artifact $mavenId: $e")
+                return
+            }
 
         if (outputApiLocation.publicApiFile.exists()) {
             project.logger.lifecycle("Regenerating $mavenId")
+            val projectXml = File(temporaryDir, "$mavenId-project.xml")
+            ProjectXml.create(
+                sourceSets,
+                project.getAndroidJar().files,
+                compiledSources,
+                projectXml
+            )
             generateApi(
                 project.getMetalavaClasspath(),
-                null,
-                inputs,
+                projectXml,
+                sourceSets.flatMap { it.sourcePaths.files },
                 outputApiLocation,
                 ApiLintMode.Skip,
                 generateRestrictToLibraryGroupAPIs,
@@ -187,16 +193,32 @@
         }
     }
 
-    private fun getFiles(runnerProject: Project, mavenId: String): CompilationInputs {
+    /**
+     * For the given [mavenId], returns a pair with the source jar as the first element, and
+     * [SourceSetInputs] representing the unzipped sources as the second element.
+     */
+    private fun getFiles(
+        runnerProject: Project,
+        mavenId: String
+    ): Pair<File, List<SourceSetInputs>> {
         val jars = getJars(runnerProject, mavenId)
-        val sources = getSources(runnerProject, "$mavenId:sources")
+        val sourcesMavenId = "$mavenId:sources"
+        val compiledSources = getCompiledSources(runnerProject, sourcesMavenId)
+        val sources = getSources(runnerProject, sourcesMavenId, compiledSources)
 
         // TODO(b/330721660) parse META-INF/kotlin-project-structure-metadata.json for KMP projects
-        return StandardCompilationInputs(
-            sourcePaths = sources,
-            dependencyClasspath = jars,
-            bootClasspath = project.getAndroidJar()
-        )
+        // Represent the project as a single source set.
+        return compiledSources to
+            listOf(
+                SourceSetInputs(
+                    // Since there's just one source set, the name is arbitrary.
+                    sourceSetName = "main",
+                    // There are no other source sets to depend on.
+                    dependsOnSourceSets = emptyList(),
+                    sourcePaths = sources,
+                    dependencyClasspath = jars,
+                )
+            )
     }
 
     private fun getJars(runnerProject: Project, mavenId: String): FileCollection {
@@ -230,18 +252,27 @@
         return runnerProject.files()
     }
 
-    private fun getSources(runnerProject: Project, mavenId: String): FileCollection {
+    /** Returns the source jar for the [mavenId]. */
+    private fun getCompiledSources(runnerProject: Project, mavenId: String): File {
         val configuration =
             runnerProject.configurations.detachedConfiguration(
                 runnerProject.dependencies.create(mavenId)
             )
         configuration.isTransitive = false
+        return configuration.singleFile
+    }
 
+    /** Returns a file collection containing the unzipped sources from [compiledSources]. */
+    private fun getSources(
+        runnerProject: Project,
+        mavenId: String,
+        compiledSources: File
+    ): FileCollection {
         val sanitizedMavenId = mavenId.replace(":", "-")
         @Suppress("DEPRECATION")
         val unzippedDir = File("${runnerProject.buildDir.path}/sources-unzipped/$sanitizedMavenId")
         runnerProject.copy { copySpec ->
-            copySpec.from(runnerProject.zipTree(configuration.singleFile))
+            copySpec.from(runnerProject.zipTree(compiledSources))
             copySpec.into(unzippedDir)
         }
         return project.files(unzippedDir)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
index 3b6d269..fcc8eaa 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/UpdateBaselineTasks.kt
@@ -55,8 +55,6 @@
         val baselineFile = baselines.get().apiLintFile
         val checkArgs =
             getGenerateApiArgs(
-                bootClasspath,
-                dependencyClasspath,
                 createProjectXmlFile(),
                 sourcePaths.files.filter { it.exists() },
                 null,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
index 2f84338..0c80536 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraFactoryProvider.kt
@@ -96,9 +96,6 @@
         Debug.traceStart { "Create CameraPipe" }
         val timeSource = SystemTimeSource()
         val start = Timestamps.now(timeSource)
-        // Enable pruning device manager when tested in the MH lab.
-        val usePruningDeviceManager =
-            android.util.Log.isLoggable(CAMERA_PIPE_MH_FLAG, android.util.Log.DEBUG)
 
         val cameraPipe =
             CameraPipe(
@@ -110,16 +107,11 @@
                             sharedInteropCallbacks.sessionStateCallback,
                             openRetryMaxTimeout
                         ),
-                    usePruningDeviceManager = usePruningDeviceManager
+                    usePruningDeviceManager = true
                 )
             )
         Log.debug { "Created CameraPipe in ${start.measureNow(timeSource).formatMs()}" }
         Debug.traceStop()
         return cameraPipe
     }
-
-    private companion object {
-        // Flag set when being tested in the lab. Refer to CameraPipeConfigTestRule for more info.
-        const val CAMERA_PIPE_MH_FLAG = "CameraPipeMH"
-    }
 }
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
index ab6cf33..3191f91 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
@@ -455,7 +455,7 @@
         int defaultStrength = mCamera.getCameraInfo().getTorchStrengthLevel().getValue();
         // If the default strength is the max, set the strength to 1, otherwise, set to max.
         int customizedStrength = defaultStrength == maxStrength ? 1 : maxStrength;
-        camera2CameraControlImpl.setTorchStrengthLevelAsync(customizedStrength).get();
+        camera2CameraControlImpl.setTorchStrengthLevel(customizedStrength).get();
 
         // Assert: the customized strength is applied
         Camera2ImplConfig camera2Config = new Camera2ImplConfig(
@@ -483,7 +483,7 @@
 
         // Act & Assert
         try {
-            camera2CameraControlImpl.setTorchStrengthLevelAsync(0).get();
+            camera2CameraControlImpl.setTorchStrengthLevel(0).get();
         } catch (ExecutionException e) {
             assertThat(e.getCause()).isInstanceOf(IllegalArgumentException.class);
             return;
@@ -510,7 +510,7 @@
 
         // Act & Assert
         try {
-            camera2CameraControlImpl.setTorchStrengthLevelAsync(
+            camera2CameraControlImpl.setTorchStrengthLevel(
                     mCamera.getCameraInfo().getMaxTorchStrengthLevel() + 1).get();
         } catch (ExecutionException e) {
             assertThat(e.getCause()).isInstanceOf(IllegalArgumentException.class);
@@ -631,7 +631,7 @@
         int defaultStrength = mCamera.getCameraInfo().getTorchStrengthLevel().getValue();
         // If the default strength is the max, set the strength to 1, otherwise, set to max.
         int customizedStrength = defaultStrength == maxStrength ? 1 : maxStrength;
-        camera2CameraControlImpl.setTorchStrengthLevelAsync(customizedStrength).get();
+        camera2CameraControlImpl.setTorchStrengthLevel(customizedStrength).get();
 
         // Assert: the capture uses default torch strength
         CaptureConfig.Builder captureConfigBuilder = new CaptureConfig.Builder();
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
index d6321f2..fa9b4f7 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
@@ -510,7 +510,7 @@
     }
 
     @Override
-    public @NonNull ListenableFuture<Void> setTorchStrengthLevelAsync(
+    public @NonNull ListenableFuture<Void> setTorchStrengthLevel(
             @IntRange(from = 1) int torchStrengthLevel) {
         if (!isControlInUse()) {
             return Futures.immediateFailedFuture(
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index ee229d04..002f57a 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -18,7 +18,7 @@
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
-    method public default com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setTorchStrengthLevelAsync(@IntRange(from=1) int);
+    method public default com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setTorchStrengthLevel(@IntRange(from=1) int);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
     method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
   }
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index ee229d04..002f57a 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -18,7 +18,7 @@
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
-    method public default com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setTorchStrengthLevelAsync(@IntRange(from=1) int);
+    method public default com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setTorchStrengthLevel(@IntRange(from=1) int);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
     method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
   }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraControl.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraControl.java
index 2332ad6..d0ab733 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraControl.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraControl.java
@@ -253,7 +253,8 @@
      * @return a {@link ListenableFuture} that is completed when the torch strength has been
      * applied.
      */
-    default @NonNull ListenableFuture<Void> setTorchStrengthLevelAsync(
+    @SuppressWarnings("AsyncSuffixFuture")
+    default @NonNull ListenableFuture<Void> setTorchStrengthLevel(
             @IntRange(from = 1) int torchStrengthLevel) {
         return Futures.immediateFailedFuture(new UnsupportedOperationException(
                 "Setting torch strength is not supported on the device."));
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
index cd2f8a2..a952344 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraInfo.java
@@ -447,7 +447,7 @@
      * Returns the {@link LiveData} of the torch strength level.
      *
      * <p>The value of the {@link LiveData} will be the default torch strength level of this
-     * device if {@link CameraControl#setTorchStrengthLevelAsync(int)} hasn't been called.
+     * device if {@link CameraControl#setTorchStrengthLevel(int)} hasn't been called.
      *
      * <p>The value of the {@link LiveData} will be {@link #TORCH_STRENGTH_LEVEL_UNSUPPORTED} if
      * the device doesn't have a flash unit or doesn't support configuring torch strength.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraControl.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraControl.java
index b39ebca..f18d111 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraControl.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ForwardingCameraControl.java
@@ -84,9 +84,9 @@
     }
 
     @Override
-    public @NonNull ListenableFuture<Void> setTorchStrengthLevelAsync(
+    public @NonNull ListenableFuture<Void> setTorchStrengthLevel(
             @IntRange(from = 1) int torchStrengthLevel) {
-        return mCameraControlInternal.setTorchStrengthLevelAsync(torchStrengthLevel);
+        return mCameraControlInternal.setTorchStrengthLevel(torchStrengthLevel);
     }
 
     @Override
diff --git a/compose/animation/animation-core/proguard-rules.pro b/compose/animation/animation-core/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/animation/animation-core/proguard-rules.pro
+++ b/compose/animation/animation-core/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index 0576ad7..7b4c673 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -111,81 +111,81 @@
     method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier weight(androidx.compose.ui.Modifier, @FloatRange(from=0.0, fromInclusive=false) float weight, optional boolean fill);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeightInLine();
-    method public float getMaxWidth();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeightInLine;
-    property public abstract float maxWidth;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeightInLine();
+    method @Deprecated public float getMaxWidth();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeightInLine;
+    property @Deprecated public abstract float maxWidth;
   }
 
   public final class ContextualFlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
-    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);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeight();
-    method public float getMaxWidthInLine();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeight;
-    property public abstract float maxWidthInLine;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
+    method @Deprecated @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);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeight();
+    method @Deprecated public float getMaxWidthInLine();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeight;
+    property @Deprecated public abstract float maxWidthInLine;
   }
 
   @SuppressCompatibility @kotlin.RequiresOptIn(message="The API of this layout is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalLayoutApi {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
   }
 
-  public static final class FlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class FlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnScope {
@@ -200,24 +200,26 @@
   }
 
   public final class FlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
   }
 
-  public static final class FlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
+  @Deprecated public static final class FlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowScope {
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 1a68ea9..438f4c8 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -116,81 +116,81 @@
     method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier weight(androidx.compose.ui.Modifier, @FloatRange(from=0.0, fromInclusive=false) float weight, optional boolean fill);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowColumnOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowColumnOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeightInLine();
-    method public float getMaxWidth();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeightInLine;
-    property public abstract float maxWidth;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowColumnScope extends androidx.compose.foundation.layout.ColumnScope {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.ui.Modifier fillMaxColumnWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeightInLine();
+    method @Deprecated public float getMaxWidth();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeightInLine;
+    property @Deprecated public abstract float maxWidth;
   }
 
   public final class ContextualFlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowColumn(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowColumnOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowColumnScope,? super java.lang.Integer,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void ContextualFlowRow(int itemCount, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.ContextualFlowRowOverflow overflow, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.layout.ContextualFlowRowScope,? super java.lang.Integer,kotlin.Unit> content);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class ContextualFlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.ContextualFlowRowOverflow.Companion Companion;
   }
 
-  public static final class ContextualFlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class ContextualFlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.ContextualFlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ContextualFlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.ContextualFlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.ContextualFlowRowOverflow Visible;
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowOverflowScope {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
-    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);
-    method public int getIndexInLine();
-    method public int getLineIndex();
-    method public float getMaxHeight();
-    method public float getMaxWidthInLine();
-    property public abstract int indexInLine;
-    property public abstract int lineIndex;
-    property public abstract float maxHeight;
-    property public abstract float maxWidthInLine;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface ContextualFlowRowScope extends androidx.compose.foundation.layout.RowScope {
+    method @Deprecated @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);
+    method @Deprecated public int getIndexInLine();
+    method @Deprecated public int getLineIndex();
+    method @Deprecated public float getMaxHeight();
+    method @Deprecated public float getMaxWidthInLine();
+    property @Deprecated public abstract int indexInLine;
+    property @Deprecated public abstract int lineIndex;
+    property @Deprecated public abstract float maxHeight;
+    property @Deprecated public abstract float maxWidthInLine;
   }
 
   @SuppressCompatibility @kotlin.RequiresOptIn(message="The API of this layout is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalLayoutApi {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowColumnOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowColumnOverflow.Companion Companion;
   }
 
-  public static final class FlowColumnOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public static final class FlowColumnOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowColumnOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnOverflowScope,kotlin.Unit> collapseIndicator, optional int minColumnsToShowCollapse, optional float minWidthToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowColumnOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowColumnOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowColumnOverflowScope extends androidx.compose.foundation.layout.FlowColumnScope {
@@ -205,26 +205,28 @@
   }
 
   public final class FlowLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, optional androidx.compose.foundation.layout.FlowColumnOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowColumn(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Alignment.Horizontal itemHorizontalAlignment, optional int maxItemsInEachColumn, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowColumnScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, optional androidx.compose.foundation.layout.FlowRowOverflow overflow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FlowRow(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, optional androidx.compose.ui.Alignment.Vertical itemVerticalAlignment, optional int maxItemsInEachRow, optional int maxLines, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static androidx.compose.ui.layout.MeasurePolicy columnMeasurementHelper(androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, int maxItemsInMainAxis);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static androidx.compose.ui.layout.MeasurePolicy rowMeasurementHelper(androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, androidx.compose.foundation.layout.Arrangement.Vertical verticalArrangement, int maxItemsInMainAxis);
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public abstract sealed class FlowLayoutOverflow {
   }
 
-  @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
-    field public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
+  @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final class FlowRowOverflow extends androidx.compose.foundation.layout.FlowLayoutOverflow {
+    field @Deprecated public static final androidx.compose.foundation.layout.FlowRowOverflow.Companion Companion;
   }
 
-  public static final class FlowRowOverflow.Companion {
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
-    method @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
-    property @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
+  @Deprecated public static final class FlowRowOverflow.Companion {
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow expandIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> content);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.FlowRowOverflow expandOrCollapseIndicator(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> expandIndicator, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.FlowRowOverflowScope,kotlin.Unit> collapseIndicator, optional int minRowsToShowCollapse, optional float minHeightToShowCollapse);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getClip();
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public androidx.compose.foundation.layout.FlowRowOverflow getVisible();
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Clip;
+    property @Deprecated @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi public final androidx.compose.foundation.layout.FlowRowOverflow Visible;
   }
 
   @SuppressCompatibility @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public interface FlowRowOverflowScope extends androidx.compose.foundation.layout.FlowRowScope {
diff --git a/compose/foundation/foundation-layout/proguard-rules.pro b/compose/foundation/foundation-layout/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/foundation/foundation-layout/proguard-rules.pro
+++ b/compose/foundation/foundation-layout/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
index 6a7c208..96dae13 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowColumnSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
index f0eda4d..d10e927 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/ContextualFlowRowSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
index ca95c71..5b45c21 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowColumnSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
index 15f5304..cd41109 100644
--- a/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
+++ b/compose/foundation/foundation-layout/samples/src/main/java/androidx/compose/foundation/layout/samples/FlowRowSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
index 086f752..1ee8cd1 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/ContextualFlowRowColumnTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.compose.foundation.background
diff --git a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
index 9c2a063..f7038c5 100644
--- a/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
+++ b/compose/foundation/foundation-layout/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/layout/FlowRowColumnTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.compose.foundation.background
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/AlignmentLine.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/AlignmentLine.kt
index fb9ac8c05..99d2381 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/AlignmentLine.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/AlignmentLine.kt
@@ -33,6 +33,7 @@
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.isSpecified
 import androidx.compose.ui.unit.isUnspecified
 import kotlin.math.max
 
@@ -142,14 +143,14 @@
 @Stable
 fun Modifier.paddingFromBaseline(top: Dp = Dp.Unspecified, bottom: Dp = Dp.Unspecified) =
     this.then(
-            if (top != Dp.Unspecified) {
+            if (top.isSpecified) {
                 Modifier.paddingFrom(FirstBaseline, before = top)
             } else {
                 Modifier
             }
         )
         .then(
-            if (bottom != Dp.Unspecified) {
+            if (bottom.isSpecified) {
                 Modifier.paddingFrom(LastBaseline, after = bottom)
             } else {
                 Modifier
@@ -192,8 +193,8 @@
 ) : ModifierNodeElement<AlignmentLineOffsetDpNode>() {
     init {
         requirePrecondition(
-            (before.value >= 0f || before == Dp.Unspecified) &&
-                (after.value >= 0f || after == Dp.Unspecified)
+            (before.value >= 0f || before.isUnspecified) and
+                (after.value >= 0f || after.isUnspecified)
         ) {
             "Padding from alignment line must be a non-negative number"
         }
@@ -319,12 +320,12 @@
     val axisMax = if (alignmentLine.horizontal) constraints.maxHeight else constraints.maxWidth
     // Compute padding required to satisfy the total before and after offsets.
     val paddingBefore =
-        ((if (before != Dp.Unspecified) before.roundToPx() else 0) - linePosition).coerceIn(
+        ((if (before.isSpecified) before.roundToPx() else 0) - linePosition).coerceIn(
             0,
             axisMax - axis
         )
     val paddingAfter =
-        ((if (after != Dp.Unspecified) after.roundToPx() else 0) - axis + linePosition).coerceIn(
+        ((if (after.isSpecified) after.roundToPx() else 0) - axis + linePosition).coerceIn(
             0,
             axisMax - axis - paddingBefore
         )
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
index a22b962..885285d 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/ContextualFlowLayout.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.annotation.FloatRange
@@ -62,6 +64,7 @@
  * @see FlowRow
  * @see ContextualFlowColumn
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @Composable
 @ExperimentalLayoutApi
 fun ContextualFlowRow(
@@ -136,6 +139,7 @@
  * @see FlowColumn
  * @see ContextualFlowRow
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @Composable
 @ExperimentalLayoutApi
 fun ContextualFlowColumn(
@@ -181,6 +185,7 @@
 }
 
 /** Defines the scope for items within a [ContextualFlowRow]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
@@ -248,18 +253,21 @@
 }
 
 /** Scope for the overflow [ContextualFlowRow]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
 interface ContextualFlowRowOverflowScope : FlowRowOverflowScope
 
 /** Scope for the overflow [ContextualFlowColumn]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
 interface ContextualFlowColumnOverflowScope : FlowColumnOverflowScope
 
 /** Provides a scope for items within a [ContextualFlowColumn]. */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @LayoutScopeMarker
 @Stable
 @ExperimentalLayoutApi
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
index 8417dd1..0b50860 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayout.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.annotation.FloatRange
@@ -80,9 +82,9 @@
  * @param overflow The strategy to handle overflowing items
  * @param content The content as a [RowScope]
  * @see FlowColumn
- * @see ContextualFlowRow
  * @see [androidx.compose.foundation.layout.Row]
  */
+@Deprecated("The overflow parameter has been deprecated")
 @Composable
 @ExperimentalLayoutApi
 fun FlowRow(
@@ -117,6 +119,58 @@
 }
 
 /**
+ * [FlowRow] is a layout that fills items from left to right (ltr) in LTR layouts or right to left
+ * (rtl) in RTL layouts and when it runs out of space, moves to the next "row" or "line" positioned
+ * on the bottom, and then continues filling items until the items run out.
+ *
+ * Example:
+ *
+ * @sample androidx.compose.foundation.layout.samples.SimpleFlowRow
+ *
+ * When a Modifier [RowScope.weight] is provided, it scales the item based on the number items that
+ * fall on the row it was placed in.
+ *
+ * Note that if two or more Text components are placed in a [Row], normally they should be aligned
+ * by their first baselines. [FlowRow] as a general purpose container does not do it automatically
+ * so developers need to handle this manually. This is achieved by adding a
+ * [RowScope.alignByBaseline] modifier to every such Text component. By default this modifier aligns
+ * by [androidx.compose.ui.layout.FirstBaseline]. If, however, you need to align Texts by
+ * [androidx.compose.ui.layout.LastBaseline] for example, use a more general [RowScope.alignBy]
+ * modifier.
+ *
+ * @param modifier The modifier to be applied to the Row.
+ * @param horizontalArrangement The horizontal arrangement of the layout's children.
+ * @param verticalArrangement The vertical arrangement of the layout's virtual rows.
+ * @param itemVerticalAlignment The cross axis/vertical alignment of an item in the column.
+ * @param maxItemsInEachRow The maximum number of items per row
+ * @param maxLines The max number of rows
+ * @param content The content as a [RowScope]
+ * @see FlowColumn
+ * @see [androidx.compose.foundation.layout.Row]
+ */
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+fun FlowRow(
+    modifier: Modifier = Modifier,
+    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
+    itemVerticalAlignment: Alignment.Vertical = Alignment.Top,
+    maxItemsInEachRow: Int = Int.MAX_VALUE,
+    maxLines: Int = Int.MAX_VALUE,
+    content: @Composable FlowRowScope.() -> Unit
+) =
+    FlowRow(
+        modifier,
+        horizontalArrangement,
+        verticalArrangement,
+        itemVerticalAlignment,
+        maxItemsInEachRow,
+        maxLines,
+        FlowRowOverflow.Clip,
+        content,
+    )
+
+/**
  * [FlowColumn] is a layout that fills items from top to bottom, and when it runs out of space on
  * the bottom, moves to the next "column" or "line" on the right or left based on ltr or rtl
  * layouts, and then continues filling items from top to bottom.
@@ -144,6 +198,7 @@
  * @see ContextualFlowColumn
  * @see [androidx.compose.foundation.layout.Column]
  */
+@Deprecated("The overflow parameter has been deprecated")
 @Composable
 @ExperimentalLayoutApi
 fun FlowColumn(
@@ -176,6 +231,54 @@
     Layout(contents = list, measurePolicy = measurePolicy, modifier = modifier)
 }
 
+/**
+ * [FlowColumn] is a layout that fills items from top to bottom, and when it runs out of space on
+ * the bottom, moves to the next "column" or "line" on the right or left based on ltr or rtl
+ * layouts, and then continues filling items from top to bottom.
+ *
+ * It supports ltr in LTR layouts, by placing the first column to the left, and then moving to the
+ * right It supports rtl in RTL layouts, by placing the first column to the right, and then moving
+ * to the left
+ *
+ * Example:
+ *
+ * @sample androidx.compose.foundation.layout.samples.SimpleFlowColumn
+ *
+ * When a Modifier [ColumnScope.weight] is provided, it scales the item based on the number items
+ * that fall on the column it was placed in.
+ *
+ * @param modifier The modifier to be applied to the Row.
+ * @param verticalArrangement The vertical arrangement of the layout's children.
+ * @param horizontalArrangement The horizontal arrangement of the layout's virtual columns
+ * @param itemHorizontalAlignment The cross axis/horizontal alignment of an item in the column.
+ * @param maxItemsInEachColumn The maximum number of items per column
+ * @param maxLines The max number of rows
+ * @param content The content as a [ColumnScope]
+ * @see FlowRow
+ * @see [androidx.compose.foundation.layout.Column]
+ */
+@Composable
+@ExperimentalLayoutApi
+fun FlowColumn(
+    modifier: Modifier = Modifier,
+    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
+    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    itemHorizontalAlignment: Alignment.Horizontal = Alignment.Start,
+    maxItemsInEachColumn: Int = Int.MAX_VALUE,
+    maxLines: Int = Int.MAX_VALUE,
+    content: @Composable FlowColumnScope.() -> Unit
+) =
+    FlowColumn(
+        modifier,
+        verticalArrangement,
+        horizontalArrangement,
+        itemHorizontalAlignment,
+        maxItemsInEachColumn,
+        maxLines,
+        FlowColumnOverflow.Clip,
+        content,
+    )
+
 /** Scope for the children of [FlowRow]. */
 @LayoutScopeMarker
 @Stable
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
index 956bd2c..5f056b2 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutBuildingBlocks.kt
@@ -64,6 +64,7 @@
         return ellipsisInfo
     }
 
+    @Suppress("DEPRECATION")
     fun getWrapInfo(
         nextItemHasNext: Boolean,
         nextIndexInLine: Int,
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
index 686fcc8..5912c7c 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/FlowLayoutOverflow.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.foundation.layout
 
 import androidx.collection.IntIntPair
@@ -54,6 +56,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 class FlowRowOverflow
 private constructor(
@@ -188,6 +191,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 class FlowColumnOverflow
 private constructor(
@@ -204,6 +208,8 @@
         seeMoreGetter,
         collapseGetter
     ) {
+    @Deprecated("FlowLayout overflow is no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -323,6 +329,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @ExperimentalLayoutApi
 class ContextualFlowRowOverflow
 private constructor(
@@ -340,6 +347,8 @@
         collapseGetter
     ) {
 
+    @Deprecated("FlowLayout overflow is no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -462,6 +471,7 @@
  * - [expandOrCollapseIndicator]: Extends the [expandIndicator] functionality by adding a 'Collapse'
  *   option. After expanding the content, users can choose to collapse it back to the summary view.
  */
+@Deprecated("ContextualFlowLayouts are no longer maintained")
 @ExperimentalLayoutApi
 class ContextualFlowColumnOverflow
 private constructor(
@@ -479,6 +489,8 @@
         collapseGetter
     ) {
 
+    @Deprecated("ContextualFlowLayouts are no longer maintained")
+    @ExperimentalLayoutApi
     companion object {
         /** Display all content, even if there is not enough space in the specified bounds. */
         @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -596,6 +608,7 @@
  * @see [ContextualFlowRowOverflow]
  * @see [ContextualFlowColumnOverflow]
  */
+@Deprecated("FlowLayout overflow is no longer maintained")
 @ExperimentalLayoutApi
 sealed class FlowLayoutOverflow(
     internal val type: OverflowType,
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Padding.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Padding.kt
index 24ac686..c038279 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Padding.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Padding.kt
@@ -33,6 +33,7 @@
 import androidx.compose.ui.unit.constrainHeight
 import androidx.compose.ui.unit.constrainWidth
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.isUnspecified
 import androidx.compose.ui.unit.offset
 
 /**
@@ -203,10 +204,14 @@
     ) : PaddingValues {
 
         init {
-            requirePrecondition(left.value >= 0) { "Left padding must be non-negative" }
-            requirePrecondition(top.value >= 0) { "Top padding must be non-negative" }
-            requirePrecondition(right.value >= 0) { "Right padding must be non-negative" }
-            requirePrecondition(bottom.value >= 0) { "Bottom padding must be non-negative" }
+            requirePrecondition(
+                (left.value >= 0f) and
+                    (top.value >= 0f) and
+                    (right.value >= 0f) and
+                    (bottom.value >= 0f)
+            ) {
+                "Padding must be non-negative"
+            }
         }
 
         override fun calculateLeftPadding(layoutDirection: LayoutDirection) = left
@@ -291,10 +296,11 @@
 ) : PaddingValues {
 
     init {
-        requirePrecondition(start.value >= 0) { "Start padding must be non-negative" }
-        requirePrecondition(top.value >= 0) { "Top padding must be non-negative" }
-        requirePrecondition(end.value >= 0) { "End padding must be non-negative" }
-        requirePrecondition(bottom.value >= 0) { "Bottom padding must be non-negative" }
+        requirePrecondition(
+            (start.value >= 0f) and (top.value >= 0f) and (end.value >= 0f) and (bottom.value >= 0f)
+        ) {
+            "Padding must be non-negative"
+        }
     }
 
     override fun calculateLeftPadding(layoutDirection: LayoutDirection) =
@@ -332,10 +338,10 @@
 
     init {
         requirePrecondition(
-            (start.value >= 0f || start == Dp.Unspecified) &&
-                (top.value >= 0f || top == Dp.Unspecified) &&
-                (end.value >= 0f || end == Dp.Unspecified) &&
-                (bottom.value >= 0f || bottom == Dp.Unspecified)
+            (start.value >= 0f || start.isUnspecified) and
+                (top.value >= 0f || top.isUnspecified) and
+                (end.value >= 0f || end.isUnspecified) and
+                (bottom.value >= 0f || bottom.isUnspecified)
         ) {
             "Padding must be non-negative"
         }
@@ -436,30 +442,30 @@
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
+        val leftPadding = paddingValues.calculateLeftPadding(layoutDirection)
+        val topPadding = paddingValues.calculateTopPadding()
+        val rightPadding = paddingValues.calculateRightPadding(layoutDirection)
+        val bottomPadding = paddingValues.calculateBottomPadding()
+
         requirePrecondition(
-            paddingValues.calculateLeftPadding(layoutDirection) >= 0.dp &&
-                paddingValues.calculateTopPadding() >= 0.dp &&
-                paddingValues.calculateRightPadding(layoutDirection) >= 0.dp &&
-                paddingValues.calculateBottomPadding() >= 0.dp
+            (leftPadding >= 0.dp) and
+                (topPadding >= 0.dp) and
+                (rightPadding >= 0.dp) and
+                (bottomPadding >= 0.dp)
         ) {
             "Padding must be non-negative"
         }
-        val horizontal =
-            paddingValues.calculateLeftPadding(layoutDirection).roundToPx() +
-                paddingValues.calculateRightPadding(layoutDirection).roundToPx()
-        val vertical =
-            paddingValues.calculateTopPadding().roundToPx() +
-                paddingValues.calculateBottomPadding().roundToPx()
+
+        val roundedLeftPadding = leftPadding.roundToPx()
+        val horizontal = roundedLeftPadding + rightPadding.roundToPx()
+
+        val roundedTopPadding = topPadding.roundToPx()
+        val vertical = roundedTopPadding + bottomPadding.roundToPx()
 
         val placeable = measurable.measure(constraints.offset(-horizontal, -vertical))
 
         val width = constraints.constrainWidth(placeable.width + horizontal)
         val height = constraints.constrainHeight(placeable.height + vertical)
-        return layout(width, height) {
-            placeable.place(
-                paddingValues.calculateLeftPadding(layoutDirection).roundToPx(),
-                paddingValues.calculateTopPadding().roundToPx()
-            )
-        }
+        return layout(width, height) { placeable.place(roundedLeftPadding, roundedTopPadding) }
     }
 }
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
index b221c8b..52e00de 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
@@ -39,6 +39,10 @@
 import androidx.compose.ui.unit.constrain
 import androidx.compose.ui.unit.constrainHeight
 import androidx.compose.ui.unit.constrainWidth
+import androidx.compose.ui.unit.isSpecified
+import androidx.compose.ui.util.fastCoerceAtLeast
+import androidx.compose.ui.util.fastCoerceAtMost
+import androidx.compose.ui.util.fastCoerceIn
 import androidx.compose.ui.util.fastRoundToInt
 
 /**
@@ -694,7 +698,7 @@
             val width =
                 (constraints.maxWidth * fraction)
                     .fastRoundToInt()
-                    .coerceIn(constraints.minWidth, constraints.maxWidth)
+                    .fastCoerceIn(constraints.minWidth, constraints.maxWidth)
             minWidth = width
             maxWidth = width
         } else {
@@ -707,7 +711,7 @@
             val height =
                 (constraints.maxHeight * fraction)
                     .fastRoundToInt()
-                    .coerceIn(constraints.minHeight, constraints.maxHeight)
+                    .fastCoerceIn(constraints.minHeight, constraints.maxHeight)
             minHeight = height
             maxHeight = height
         } else {
@@ -782,28 +786,28 @@
     private val Density.targetConstraints: Constraints
         get() {
             val maxWidth =
-                if (maxWidth != Dp.Unspecified) {
-                    maxWidth.roundToPx().coerceAtLeast(0)
+                if (maxWidth.isSpecified) {
+                    maxWidth.roundToPx().fastCoerceAtLeast(0)
                 } else {
                     Constraints.Infinity
                 }
             val maxHeight =
-                if (maxHeight != Dp.Unspecified) {
-                    maxHeight.roundToPx().coerceAtLeast(0)
+                if (maxHeight.isSpecified) {
+                    maxHeight.roundToPx().fastCoerceAtLeast(0)
                 } else {
                     Constraints.Infinity
                 }
             val minWidth =
-                if (minWidth != Dp.Unspecified) {
-                    minWidth.roundToPx().coerceAtMost(maxWidth).coerceAtLeast(0).let {
+                if (minWidth.isSpecified) {
+                    minWidth.roundToPx().fastCoerceIn(0, maxWidth).let {
                         if (it != Constraints.Infinity) it else 0
                     }
                 } else {
                     0
                 }
             val minHeight =
-                if (minHeight != Dp.Unspecified) {
-                    minHeight.roundToPx().coerceAtMost(maxHeight).coerceAtLeast(0).let {
+                if (minHeight.isSpecified) {
+                    minHeight.roundToPx().fastCoerceIn(0, maxHeight).let {
                         if (it != Constraints.Infinity) it else 0
                     }
                 } else {
@@ -827,28 +831,28 @@
                     constraints.constrain(targetConstraints)
                 } else {
                     val resolvedMinWidth =
-                        if (minWidth != Dp.Unspecified) {
+                        if (minWidth.isSpecified) {
                             targetConstraints.minWidth
                         } else {
-                            constraints.minWidth.coerceAtMost(targetConstraints.maxWidth)
+                            constraints.minWidth.fastCoerceAtMost(targetConstraints.maxWidth)
                         }
                     val resolvedMaxWidth =
-                        if (maxWidth != Dp.Unspecified) {
+                        if (maxWidth.isSpecified) {
                             targetConstraints.maxWidth
                         } else {
-                            constraints.maxWidth.coerceAtLeast(targetConstraints.minWidth)
+                            constraints.maxWidth.fastCoerceAtLeast(targetConstraints.minWidth)
                         }
                     val resolvedMinHeight =
-                        if (minHeight != Dp.Unspecified) {
+                        if (minHeight.isSpecified) {
                             targetConstraints.minHeight
                         } else {
-                            constraints.minHeight.coerceAtMost(targetConstraints.maxHeight)
+                            constraints.minHeight.fastCoerceAtMost(targetConstraints.maxHeight)
                         }
                     val resolvedMaxHeight =
-                        if (maxHeight != Dp.Unspecified) {
+                        if (maxHeight.isSpecified) {
                             targetConstraints.maxHeight
                         } else {
-                            constraints.maxHeight.coerceAtLeast(targetConstraints.minHeight)
+                            constraints.maxHeight.fastCoerceAtLeast(targetConstraints.minHeight)
                         }
                     Constraints(
                         resolvedMinWidth,
@@ -1072,14 +1076,14 @@
     ): MeasureResult {
         val wrappedConstraints =
             Constraints(
-                if (minWidth != Dp.Unspecified && constraints.minWidth == 0) {
-                    minWidth.roundToPx().coerceAtMost(constraints.maxWidth).coerceAtLeast(0)
+                if (minWidth.isSpecified && constraints.minWidth == 0) {
+                    minWidth.roundToPx().fastCoerceIn(0, constraints.maxWidth)
                 } else {
                     constraints.minWidth
                 },
                 constraints.maxWidth,
-                if (minHeight != Dp.Unspecified && constraints.minHeight == 0) {
-                    minHeight.roundToPx().coerceAtMost(constraints.maxHeight).coerceAtLeast(0)
+                if (minHeight.isSpecified && constraints.minHeight == 0) {
+                    minHeight.roundToPx().fastCoerceIn(0, constraints.maxHeight)
                 } else {
                     constraints.minHeight
                 },
@@ -1095,7 +1099,7 @@
     ) =
         measurable
             .minIntrinsicWidth(height)
-            .coerceAtLeast(if (minWidth != Dp.Unspecified) minWidth.roundToPx() else 0)
+            .fastCoerceAtLeast(if (minWidth.isSpecified) minWidth.roundToPx() else 0)
 
     override fun IntrinsicMeasureScope.maxIntrinsicWidth(
         measurable: IntrinsicMeasurable,
@@ -1103,7 +1107,7 @@
     ) =
         measurable
             .maxIntrinsicWidth(height)
-            .coerceAtLeast(if (minWidth != Dp.Unspecified) minWidth.roundToPx() else 0)
+            .fastCoerceAtLeast(if (minWidth.isSpecified) minWidth.roundToPx() else 0)
 
     override fun IntrinsicMeasureScope.minIntrinsicHeight(
         measurable: IntrinsicMeasurable,
@@ -1111,7 +1115,7 @@
     ) =
         measurable
             .minIntrinsicHeight(width)
-            .coerceAtLeast(if (minHeight != Dp.Unspecified) minHeight.roundToPx() else 0)
+            .fastCoerceAtLeast(if (minHeight.isSpecified) minHeight.roundToPx() else 0)
 
     override fun IntrinsicMeasureScope.maxIntrinsicHeight(
         measurable: IntrinsicMeasurable,
@@ -1119,7 +1123,7 @@
     ) =
         measurable
             .maxIntrinsicHeight(width)
-            .coerceAtLeast(if (minHeight != Dp.Unspecified) minHeight.roundToPx() else 0)
+            .fastCoerceAtLeast(if (minHeight.isSpecified) minHeight.roundToPx() else 0)
 }
 
 internal enum class Direction {
diff --git a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSlotsReuseTest.kt b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSlotsReuseTest.kt
index d988a6a..5b743a5a 100644
--- a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSlotsReuseTest.kt
+++ b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSlotsReuseTest.kt
@@ -59,7 +59,7 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
 
         rule.runOnIdle { runBlocking { state.scrollToItem(1) } }
@@ -78,8 +78,8 @@
             }
         }
         // Semantics IDs must be fetched before scrolling.
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
         rule.onNodeWithTag("1").assertIsDisplayed()
 
@@ -105,7 +105,7 @@
         }
         val deactivatedIds = mutableListOf<Int>()
         repeat(DefaultMaxItemsToRetain) {
-            deactivatedIds.add(rule.onNodeWithTag("$it").semanticsId())
+            deactivatedIds.add(rule.onNodeWithTag("$it").fetchSemanticsNode().id)
         }
 
         rule.runOnIdle { runBlocking { state.scrollToItem(DefaultMaxItemsToRetain + 1) } }
@@ -127,8 +127,8 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
         rule.onNodeWithTag("1").assertIsDisplayed()
 
@@ -172,7 +172,7 @@
         }
 
         // 3 should be visible at this point, so save its ID to check later
-        val id3 = rule.onNodeWithTag("3").semanticsId()
+        val id3 = rule.onNodeWithTag("3").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -204,8 +204,8 @@
             }
         }
 
-        val id10 = rule.onNodeWithTag("10").semanticsId()
-        val id11 = rule.onNodeWithTag("11").semanticsId()
+        val id10 = rule.onNodeWithTag("10").fetchSemanticsNode().id
+        val id11 = rule.onNodeWithTag("11").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -238,7 +238,7 @@
             }
         }
         // 8 should be visible at this point, so save its ID to check later
-        val id8 = rule.onNodeWithTag("8").semanticsId()
+        val id8 = rule.onNodeWithTag("8").fetchSemanticsNode().id
         rule.runOnIdle {
             runBlocking {
                 state.scrollToItem(6) // 9 reused, buffer is [8]
@@ -294,8 +294,8 @@
         }
 
         // 2 and 3 should be visible at this point, so save its ID to check later
-        val id2 = rule.onNodeWithTag("2").semanticsId()
-        val id3 = rule.onNodeWithTag("3").semanticsId()
+        val id2 = rule.onNodeWithTag("2").fetchSemanticsNode().id
+        val id3 = rule.onNodeWithTag("3").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -341,7 +341,7 @@
 
         val deactivatedIds = mutableListOf<Int>()
         for (i in 0 until visibleItemsCount) {
-            deactivatedIds.add(rule.onNodeWithTag("$i").semanticsId())
+            deactivatedIds.add(rule.onNodeWithTag("$i").fetchSemanticsNode().id)
             rule.onNodeWithTag("$i").assertIsDisplayed()
         }
         for (i in startOfType1 until startOfType1 + DefaultMaxItemsToRetain) {
@@ -382,8 +382,8 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -418,4 +418,4 @@
     }
 }
 
-private val DefaultMaxItemsToRetain = 7
+private const val DefaultMaxItemsToRetain = 7
diff --git a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListSlotsReuseTest.kt b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListSlotsReuseTest.kt
index 0ab752c..85af651 100644
--- a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListSlotsReuseTest.kt
+++ b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListSlotsReuseTest.kt
@@ -65,7 +65,7 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
 
         rule.runOnIdle { runBlocking { state.scrollToItem(1) } }
@@ -86,8 +86,8 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
         rule.onNodeWithTag("1").assertIsDisplayed()
 
@@ -112,7 +112,7 @@
         // Semantics IDs must be fetched before scrolling.
         val deactivatedIds = mutableListOf<Int>()
         repeat(DefaultMaxItemsToRetain) {
-            deactivatedIds.add(rule.onNodeWithTag("$it").semanticsId())
+            deactivatedIds.add(rule.onNodeWithTag("$it").fetchSemanticsNode().id)
         }
 
         rule.runOnIdle { runBlocking { state.scrollToItem(DefaultMaxItemsToRetain + 1) } }
@@ -136,8 +136,8 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
         rule.onNodeWithTag("0").assertIsDisplayed()
         rule.onNodeWithTag("1").assertIsDisplayed()
 
@@ -183,7 +183,7 @@
         }
 
         // 3 should be visible at this point, so save its ID to check later
-        val id3 = rule.onNodeWithTag("3").semanticsId()
+        val id3 = rule.onNodeWithTag("3").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -217,8 +217,8 @@
             }
         }
 
-        val id10 = rule.onNodeWithTag("10").semanticsId()
-        val id11 = rule.onNodeWithTag("11").semanticsId()
+        val id10 = rule.onNodeWithTag("10").fetchSemanticsNode().id
+        val id11 = rule.onNodeWithTag("11").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -253,7 +253,7 @@
             }
         }
         // 8 should be visible at this point, so save its ID to check later
-        val id8 = rule.onNodeWithTag("8").semanticsId()
+        val id8 = rule.onNodeWithTag("8").fetchSemanticsNode().id
         rule.runOnIdle {
             runBlocking {
                 state.scrollToItem(6) // 9 reused, buffer is [8]
@@ -314,8 +314,8 @@
         }
 
         // 2 and 3 should be visible at this point, so save its ID to check later
-        val id2 = rule.onNodeWithTag("2").semanticsId()
-        val id3 = rule.onNodeWithTag("3").semanticsId()
+        val id2 = rule.onNodeWithTag("2").fetchSemanticsNode().id
+        val id3 = rule.onNodeWithTag("3").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -357,7 +357,7 @@
 
         val deactivatedIds = mutableListOf<Int>()
         for (i in 0 until visibleItemsCount) {
-            deactivatedIds.add(rule.onNodeWithTag("$i").semanticsId())
+            deactivatedIds.add(rule.onNodeWithTag("$i").fetchSemanticsNode().id)
             rule.onNodeWithTag("$i").assertIsDisplayed()
         }
         for (i in startOfType1 until startOfType1 + DefaultMaxItemsToRetain) {
@@ -398,8 +398,8 @@
             }
         }
 
-        val id0 = rule.onNodeWithTag("0").semanticsId()
-        val id1 = rule.onNodeWithTag("1").semanticsId()
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
+        val id1 = rule.onNodeWithTag("1").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -434,4 +434,4 @@
     }
 }
 
-private val DefaultMaxItemsToRetain = 7
+private const val DefaultMaxItemsToRetain = 7
diff --git a/compose/foundation/foundation/proguard-rules.pro b/compose/foundation/foundation/proguard-rules.pro
index d07663a..d2c7182 100644
--- a/compose/foundation/foundation/proguard-rules.pro
+++ b/compose/foundation/foundation/proguard-rules.pro
@@ -15,8 +15,9 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     # For methods returning Nothing
     static java.lang.Void throw*Exception(...);
 }
+
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
index bc90119..9757d4a 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
@@ -139,6 +139,14 @@
     }
 
     @Test
+    fun textField_newLineNumpad() {
+        keysSequenceTest(initText = "hello") {
+            Key.NumPadEnter.downAndUp()
+            expectedText("\nhello")
+        }
+    }
+
+    @Test
     fun textField_backspace() {
         keysSequenceTest(initText = "hello") {
             Key.DirectionRight.downAndUp()
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
index d22ae99..52f59db 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
@@ -66,6 +66,7 @@
     actual val MoveEnd: Key = Key(AndroidKeyEvent.KEYCODE_MOVE_END)
     actual val Insert: Key = Key(AndroidKeyEvent.KEYCODE_INSERT)
     actual val Enter: Key = Key(AndroidKeyEvent.KEYCODE_ENTER)
+    actual val NumPadEnter: Key = Key(AndroidKeyEvent.KEYCODE_NUMPAD_ENTER)
     actual val Backspace: Key = Key(AndroidKeyEvent.KEYCODE_DEL)
     actual val Delete: Key = Key(AndroidKeyEvent.KEYCODE_FORWARD_DEL)
     actual val Paste: Key = Key(AndroidKeyEvent.KEYCODE_PASTE)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 7a034224..7c73fa8 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -443,44 +443,28 @@
         measurable: IntrinsicMeasurable,
         height: Int
     ): Int {
-        return if (isVertical) {
-            measurable.minIntrinsicWidth(Constraints.Infinity)
-        } else {
-            measurable.minIntrinsicWidth(height)
-        }
+        return measurable.minIntrinsicWidth(if (isVertical) Constraints.Infinity else height)
     }
 
     override fun IntrinsicMeasureScope.minIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
     ): Int {
-        return if (isVertical) {
-            measurable.minIntrinsicHeight(width)
-        } else {
-            measurable.minIntrinsicHeight(Constraints.Infinity)
-        }
+        return measurable.minIntrinsicHeight(if (isVertical) width else Constraints.Infinity)
     }
 
     override fun IntrinsicMeasureScope.maxIntrinsicWidth(
         measurable: IntrinsicMeasurable,
         height: Int
     ): Int {
-        return if (isVertical) {
-            measurable.maxIntrinsicWidth(Constraints.Infinity)
-        } else {
-            measurable.maxIntrinsicWidth(height)
-        }
+        return measurable.maxIntrinsicWidth(if (isVertical) Constraints.Infinity else height)
     }
 
     override fun IntrinsicMeasureScope.maxIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
     ): Int {
-        return if (isVertical) {
-            measurable.maxIntrinsicHeight(width)
-        } else {
-            measurable.maxIntrinsicHeight(Constraints.Infinity)
-        }
+        return measurable.maxIntrinsicHeight(if (isVertical) width else Constraints.Infinity)
     }
 
     override fun SemanticsPropertyReceiver.applySemantics() {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
index dd3ef0b..bdbe702 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
@@ -1650,7 +1650,7 @@
     }
 }
 
-internal expect inline fun assertOnJvm(statement: Boolean, message: () -> String): Unit
+internal expect inline fun assertOnJvm(statement: Boolean, message: () -> String)
 
 internal val AnchoredDraggableMinFlingVelocity = 125.dp
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/internal/InlineClassHelper.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/internal/InlineClassHelper.kt
index 4af862a..686d885 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/internal/InlineClassHelper.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/internal/InlineClassHelper.kt
@@ -53,7 +53,7 @@
     }
 }
 
-@Suppress("NOTHING_TO_INLINE", "BanInlineOptIn")
+@Suppress("NOTHING_TO_INLINE", "BanInlineOptIn", "KotlinRedundantDiagnosticSuppress")
 @OptIn(ExperimentalContracts::class)
 internal inline fun checkPrecondition(value: Boolean) {
     contract { returns() implies value }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt
index 153b5da..2764e2e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt
@@ -51,6 +51,7 @@
     val MoveEnd: Key
     val Insert: Key
     val Enter: Key
+    val NumPadEnter: Key
     val Backspace: Key
     val Delete: Key
     val Paste: Key
@@ -104,7 +105,8 @@
                         MappedKeys.PageDown -> KeyCommand.PAGE_DOWN
                         MappedKeys.MoveHome -> KeyCommand.LINE_START
                         MappedKeys.MoveEnd -> KeyCommand.LINE_END
-                        MappedKeys.Enter -> KeyCommand.NEW_LINE
+                        MappedKeys.Enter,
+                        MappedKeys.NumPadEnter -> KeyCommand.NEW_LINE
                         MappedKeys.Backspace -> KeyCommand.DELETE_PREV_CHAR
                         MappedKeys.Delete -> KeyCommand.DELETE_NEXT_CHAR
                         MappedKeys.Paste -> KeyCommand.PASTE
@@ -146,8 +148,8 @@
                         }
                     event.isShiftPressed ->
                         when (event.key) {
-                            MappedKeys.MoveHome -> KeyCommand.SELECT_LINE_LEFT
-                            MappedKeys.MoveEnd -> KeyCommand.SELECT_LINE_RIGHT
+                            MappedKeys.MoveHome -> KeyCommand.SELECT_LINE_START
+                            MappedKeys.MoveEnd -> KeyCommand.SELECT_LINE_END
                             else -> null
                         }
                     event.isAltPressed ->
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/OffsetMappingCalculator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/OffsetMappingCalculator.kt
index b6fb607..eaa2856 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/OffsetMappingCalculator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/input/internal/OffsetMappingCalculator.kt
@@ -370,18 +370,18 @@
  */
 @kotlin.jvm.JvmInline
 private value class OpArray private constructor(private val values: IntArray) {
-    constructor(size: Int) : this(IntArray(size * ElementSize))
+    constructor(size: Int) : this(IntArray(size * OpArrayElementSize))
 
     val size: Int
-        get() = values.size / ElementSize
+        get() = values.size / OpArrayElementSize
 
     fun set(index: Int, offset: Int, srcLen: Int, destLen: Int) {
-        values[index * ElementSize] = offset
-        values[index * ElementSize + 1] = srcLen
-        values[index * ElementSize + 2] = destLen
+        values[index * OpArrayElementSize] = offset
+        values[index * OpArrayElementSize + 1] = srcLen
+        values[index * OpArrayElementSize + 2] = destLen
     }
 
-    fun copyOf(newSize: Int) = OpArray(values.copyOf(newSize * ElementSize))
+    fun copyOf(newSize: Int) = OpArray(values.copyOf(newSize * OpArrayElementSize))
 
     /**
      * Loops through the array between 0 and [max] (exclusive). If [reversed] is false (the
@@ -399,22 +399,20 @@
         // duplication here keeps the more complicated logic at the callsite more readable.
         if (reversed) {
             for (i in max - 1 downTo 0) {
-                val offset = values[i * ElementSize]
-                val srcLen = values[i * ElementSize + 1]
-                val destLen = values[i * ElementSize + 2]
+                val offset = values[i * OpArrayElementSize]
+                val srcLen = values[i * OpArrayElementSize + 1]
+                val destLen = values[i * OpArrayElementSize + 2]
                 block(offset, srcLen, destLen)
             }
         } else {
             for (i in 0 until max) {
-                val offset = values[i * ElementSize]
-                val srcLen = values[i * ElementSize + 1]
-                val destLen = values[i * ElementSize + 2]
+                val offset = values[i * OpArrayElementSize]
+                val srcLen = values[i * OpArrayElementSize + 1]
+                val destLen = values[i * OpArrayElementSize + 2]
                 block(offset, srcLen, destLen)
             }
         }
     }
-
-    private companion object {
-        const val ElementSize = 3
-    }
 }
+
+private const val OpArrayElementSize = 3
diff --git a/compose/foundation/foundation/src/commonStubsMain/kotlin/androidx/compose/foundation/text/KeyMapping.commonStubs.kt b/compose/foundation/foundation/src/commonStubsMain/kotlin/androidx/compose/foundation/text/KeyMapping.commonStubs.kt
index e6450f8..759faf0 100644
--- a/compose/foundation/foundation/src/commonStubsMain/kotlin/androidx/compose/foundation/text/KeyMapping.commonStubs.kt
+++ b/compose/foundation/foundation/src/commonStubsMain/kotlin/androidx/compose/foundation/text/KeyMapping.commonStubs.kt
@@ -40,6 +40,7 @@
     actual val MoveEnd: Key = implementedInJetBrainsFork()
     actual val Insert: Key = implementedInJetBrainsFork()
     actual val Enter: Key = implementedInJetBrainsFork()
+    actual val NumPadEnter: Key = implementedInJetBrainsFork()
     actual val Backspace: Key = implementedInJetBrainsFork()
     actual val Delete: Key = implementedInJetBrainsFork()
     actual val Paste: Key = implementedInJetBrainsFork()
diff --git a/compose/material3/adaptive/adaptive-layout/api/1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-layout/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..b4cd5c9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/api/1.1.0-beta01.txt
@@ -0,0 +1,469 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive.layout {
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface AdaptStrategy {
+    method public String adapt();
+    field public static final androidx.compose.material3.adaptive.layout.AdaptStrategy.Companion Companion;
+  }
+
+  public static final class AdaptStrategy.Companion {
+    method public androidx.compose.material3.adaptive.layout.AdaptStrategy getHide();
+    property public final androidx.compose.material3.adaptive.layout.AdaptStrategy Hide;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public interface AnimatedPaneOverride {
+    method @androidx.compose.runtime.Composable public <S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> void AnimatedPane(androidx.compose.material3.adaptive.layout.AnimatedPaneOverrideContext<S,T>);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public final class AnimatedPaneOverrideContext<S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> {
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getBoundsAnimationSpec();
+    method public kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> getContent();
+    method public androidx.compose.animation.EnterTransition getEnterTransition();
+    method public androidx.compose.animation.ExitTransition getExitTransition();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T> getScope();
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> boundsAnimationSpec;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> content;
+    property public final androidx.compose.animation.EnterTransition enterTransition;
+    property public final androidx.compose.animation.ExitTransition exitTransition;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T> scope;
+  }
+
+  public sealed interface AnimatedPaneScope extends androidx.compose.animation.AnimatedVisibilityScope {
+    field public static final androidx.compose.material3.adaptive.layout.AnimatedPaneScope.Companion Companion;
+  }
+
+  public static final class AnimatedPaneScope.Companion {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public androidx.compose.material3.adaptive.layout.AnimatedPaneScope create(androidx.compose.animation.AnimatedVisibilityScope animatedVisibilityScope);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ExtendedPaneScaffoldPaneScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> extends androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldScope<Role,ScaffoldValue> androidx.compose.material3.adaptive.layout.PaneScaffoldPaneScope<Role> {
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ExtendedPaneScaffoldScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> extends androidx.compose.material3.adaptive.layout.PaneScaffoldScope androidx.compose.ui.layout.LookaheadScope androidx.compose.material3.adaptive.layout.PaneScaffoldTransitionScope<Role,ScaffoldValue> {
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class HingePolicy {
+    field public static final androidx.compose.material3.adaptive.layout.HingePolicy.Companion Companion;
+  }
+
+  public static final class HingePolicy.Companion {
+    method public int getAlwaysAvoid();
+    method public int getAvoidOccluding();
+    method public int getAvoidSeparating();
+    method public int getNeverAvoid();
+    property public final int AlwaysAvoid;
+    property public final int AvoidOccluding;
+    property public final int AvoidSeparating;
+    property public final int NeverAvoid;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ListDetailPaneScaffoldDefaults {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies(optional androidx.compose.material3.adaptive.layout.AdaptStrategy detailPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy listPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy extraPaneAdaptStrategy);
+    field public static final androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldDefaults INSTANCE;
+  }
+
+  public final class ListDetailPaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  public final class ListDetailPaneScaffoldRole {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getDetail();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getExtra();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getList();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Detail;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Extra;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole List;
+    field public static final androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public final class MutableThreePaneScaffoldState extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState {
+    ctor public MutableThreePaneScaffoldState(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue initialScaffoldValue);
+    method public suspend Object? animateTo(optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float>? animationSpec, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getCurrentState();
+    method @FloatRange(from=0.0, to=1.0) public float getProgressFraction();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getTargetState();
+    method public boolean isPredictiveBackInProgress();
+    method public suspend Object? seekTo(@FloatRange(from=0.0, to=1.0) float fraction, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue currentState;
+    property public boolean isPredictiveBackInProgress;
+    property @FloatRange(from=0.0, to=1.0) public float progressFraction;
+    property public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState;
+  }
+
+  @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
+    field public static final androidx.compose.material3.adaptive.layout.PaneAdaptedValue.Companion Companion;
+  }
+
+  public static final class PaneAdaptedValue.Companion {
+    method public String getExpanded();
+    method public String getHidden();
+    property public final String Expanded;
+    property public final String Hidden;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public abstract sealed class PaneExpansionAnchor {
+    method @androidx.compose.runtime.Composable public abstract String getDescription();
+    property @androidx.compose.runtime.Composable public abstract String description;
+  }
+
+  public abstract static class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    method public final int getDirection();
+    method public final float getOffset();
+    property public final int direction;
+    property public final float offset;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromEnd(float offset);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromStart(float offset);
+  }
+
+  @kotlin.jvm.JvmInline public static final value class PaneExpansionAnchor.Offset.Direction {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Direction.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Direction.Companion {
+    method public int getFromEnd();
+    method public int getFromStart();
+    property public final int FromEnd;
+    property public final int FromStart;
+  }
+
+  public static final class PaneExpansionAnchor.Proportion extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    ctor public PaneExpansionAnchor.Proportion(@FloatRange(from=0.0, to=1.0) float proportion);
+    method @androidx.compose.runtime.Composable public String getDescription();
+    method public float getProportion();
+    property @androidx.compose.runtime.Composable public String description;
+    property @FloatRange(from=0.0, to=1.0) public final float proportion;
+  }
+
+  public final class PaneExpansionDraggableModifierKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static kotlin.jvm.functions.Function1<androidx.compose.ui.semantics.SemanticsPropertyReceiver,kotlin.Unit> defaultDragHandleSemantics(androidx.compose.material3.adaptive.layout.PaneExpansionState);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public final class PaneExpansionState {
+    method public suspend Object? animateTo(androidx.compose.material3.adaptive.layout.PaneExpansionAnchor anchor, optional float initialVelocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void clear();
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor? getCurrentAnchor();
+    method public boolean isUnspecified();
+    method public void setFirstPaneProportion(@FloatRange(from=0.0, to=1.0) float firstPaneProportion);
+    method public void setFirstPaneWidth(int firstPaneWidth);
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor? currentAnchor;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionState.Companion Companion;
+    field public static final int Unspecified = -1; // 0xffffffff
+  }
+
+  public static final class PaneExpansionState.Companion {
+    property public static final int Unspecified;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public sealed interface PaneExpansionStateKey {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionStateKey.Companion Companion;
+  }
+
+  public static final class PaneExpansionStateKey.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getDefault();
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionStateKey Default;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface PaneExpansionStateKeyProvider {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getPaneExpansionStateKey();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneExpansionStateKey paneExpansionStateKey;
+  }
+
+  public final class PaneExpansionStateKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.layout.PaneExpansionState rememberPaneExpansionState(optional androidx.compose.material3.adaptive.layout.PaneExpansionStateKey key, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor> anchors, optional int initialAnchoredIndex, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> anchoringAnimationSpec, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.layout.PaneExpansionState rememberPaneExpansionState(androidx.compose.material3.adaptive.layout.PaneExpansionStateKeyProvider keyProvider, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor> anchors, optional int initialAnchoredIndex, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> anchoringAnimationSpec, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior);
+  }
+
+  public final class PaneKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> void AnimatedPane(androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T>, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> boundsAnimationSpec, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.AnimatedPaneOverride> getLocalAnimatedPaneOverride();
+    property @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.AnimatedPaneOverride> LocalAnimatedPaneOverride;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface PaneMotion {
+    method public int getType();
+    property public abstract int type;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotion.Companion Companion;
+  }
+
+  public static final class PaneMotion.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getAnimateBounds();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromLeft();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromLeftDelayed();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromRight();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromRightDelayed();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterWithExpand();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitToLeft();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitToRight();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitWithShrink();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getNoMotion();
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion AnimateBounds;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromLeft;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromLeftDelayed;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromRight;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromRightDelayed;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterWithExpand;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitToLeft;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitToRight;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitWithShrink;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion NoMotion;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public static final value class PaneMotion.Type {
+    method public int getValue();
+    property public final int value;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotion.Type.Companion Companion;
+  }
+
+  public static final class PaneMotion.Type.Companion {
+    method public int getEntering();
+    method public int getExiting();
+    method public int getHidden();
+    method public int getShown();
+    property public final int Entering;
+    property public final int Exiting;
+    property public final int Hidden;
+    property public final int Shown;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class PaneMotionData {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getMotion();
+    method public long getOriginPosition();
+    method public long getOriginSize();
+    method public long getTargetPosition();
+    method public long getTargetSize();
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion motion;
+    property public final long originPosition;
+    property public final long originSize;
+    property public final long targetPosition;
+    property public final long targetSize;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class PaneMotionDefaults {
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getDelayedAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> getDelayedOffsetAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> getDelayedSizeAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> getOffsetAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> getSizeAnimationSpec();
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> AnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> DelayedAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> DelayedOffsetAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> DelayedSizeAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> OffsetAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> SizeAnimationSpec;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotionDefaults INSTANCE;
+  }
+
+  public final class PaneMotionKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static <Role> androidx.compose.animation.EnterTransition calculateDefaultEnterTransition(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, Role role);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static <Role> androidx.compose.animation.ExitTransition calculateDefaultExitTransition(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, Role role);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static inline <Role> void forEach(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, kotlin.jvm.functions.Function2<? super Role,? super androidx.compose.material3.adaptive.layout.PaneMotionData,kotlin.Unit> action);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static inline <Role> void forEachReversed(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, kotlin.jvm.functions.Function2<? super Role,? super androidx.compose.material3.adaptive.layout.PaneMotionData,kotlin.Unit> action);
+  }
+
+  @androidx.compose.runtime.Immutable public final class PaneScaffoldDirective {
+    ctor public PaneScaffoldDirective(int maxHorizontalPartitions, float horizontalPartitionSpacerSize, int maxVerticalPartitions, float verticalPartitionSpacerSize, float defaultPanePreferredWidth, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective copy(optional int maxHorizontalPartitions, optional float horizontalPartitionSpacerSize, optional int maxVerticalPartitions, optional float verticalPartitionSpacerSize, optional float defaultPanePreferredWidth, optional java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public float getDefaultPanePreferredWidth();
+    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
+    method public float getHorizontalPartitionSpacerSize();
+    method public int getMaxHorizontalPartitions();
+    method public int getMaxVerticalPartitions();
+    method public float getVerticalPartitionSpacerSize();
+    property public final float defaultPanePreferredWidth;
+    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
+    property public final float horizontalPartitionSpacerSize;
+    property public final int maxHorizontalPartitions;
+    property public final int maxVerticalPartitions;
+    property public final float verticalPartitionSpacerSize;
+    field public static final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective.Companion Companion;
+  }
+
+  public static final class PaneScaffoldDirective.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getDefault();
+    property public final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective Default;
+  }
+
+  public final class PaneScaffoldDirectiveKt {
+    method public static androidx.compose.material3.adaptive.layout.PaneScaffoldDirective calculatePaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int verticalHingePolicy);
+    method public static androidx.compose.material3.adaptive.layout.PaneScaffoldDirective calculatePaneScaffoldDirectiveWithTwoPanesOnMediumWidth(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int verticalHingePolicy);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldMotionDataProvider<Role> {
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotionData get(int index);
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotionData get(Role role);
+    method public int getCount();
+    method public Role getRoleAt(int index);
+    method public long getScaffoldSize();
+    property public abstract int count;
+    property public abstract long scaffoldSize;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldPaneScope<Role> {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getPaneMotion();
+    method public Role getPaneRole();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneMotion paneMotion;
+    property public abstract Role paneRole;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldParentData {
+    method public float getMinTouchTargetSize();
+    method public float getPreferredWidth();
+    method public boolean isAnimatedPane();
+    property public abstract boolean isAnimatedPane;
+    property public abstract float minTouchTargetSize;
+    property public abstract float preferredWidth;
+  }
+
+  public sealed interface PaneScaffoldScope {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public androidx.compose.ui.Modifier paneExpansionDraggable(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.layout.PaneExpansionState state, float minTouchTargetSize, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.ui.semantics.SemanticsPropertyReceiver,kotlin.Unit> semanticsProperties);
+    method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldTransitionScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> {
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role> getMotionDataProvider();
+    method @FloatRange(from=0.0, to=1.0) public float getMotionProgress();
+    method public androidx.compose.animation.core.Transition<ScaffoldValue> getScaffoldStateTransition();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role> motionDataProvider;
+    property @FloatRange(from=0.0, to=1.0) public abstract float motionProgress;
+    property public abstract androidx.compose.animation.core.Transition<ScaffoldValue> scaffoldStateTransition;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldValue<T> {
+    method public operator String get(T role);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class SupportingPaneScaffoldDefaults {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies(optional androidx.compose.material3.adaptive.layout.AdaptStrategy mainPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy supportingPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy extraPaneAdaptStrategy);
+    field public static final androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldDefaults INSTANCE;
+  }
+
+  public final class SupportingPaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  public final class SupportingPaneScaffoldRole {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getExtra();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getMain();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getSupporting();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Extra;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Main;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Supporting;
+    field public static final androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneMotion {
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotion get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    field public static final androidx.compose.material3.adaptive.layout.ThreePaneMotion.Companion Companion;
+  }
+
+  public static final class ThreePaneMotion.Companion {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneMotion getNoMotion();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneMotion NoMotion;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ThreePaneScaffoldAdaptStrategies {
+    ctor public ThreePaneScaffoldAdaptStrategies(androidx.compose.material3.adaptive.layout.AdaptStrategy primaryPaneAdaptStrategy, androidx.compose.material3.adaptive.layout.AdaptStrategy secondaryPaneAdaptStrategy, androidx.compose.material3.adaptive.layout.AdaptStrategy tertiaryPaneAdaptStrategy);
+    method public operator androidx.compose.material3.adaptive.layout.AdaptStrategy get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+  }
+
+  public final class ThreePaneScaffoldDestinationItem<T> {
+    ctor public ThreePaneScaffoldDestinationItem(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? contentKey);
+    method public T? getContentKey();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getPane();
+    property public final T? contentKey;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldHorizontalOrder {
+    method public void forEach(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public void forEachIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public void forEachIndexedReversed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public operator androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole get(int index);
+    method public int getSize();
+    method public int indexOf(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    property public int size;
+  }
+
+  public final class ThreePaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverride> getLocalThreePaneScaffoldOverride();
+    property @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverride> LocalThreePaneScaffoldOverride;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public interface ThreePaneScaffoldOverride {
+    method @androidx.compose.runtime.Composable public void ThreePaneScaffold(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverrideContext);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public final class ThreePaneScaffoldOverrideContext {
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? getPaneExpansionDragHandle();
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionState getPaneExpansionState();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder getPaneOrder();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getPrimaryPane();
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState getScaffoldState();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getSecondaryPane();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getTertiaryPane();
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle;
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionState paneExpansionState;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder paneOrder;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> primaryPane;
+    property public final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> secondaryPane;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? tertiaryPane;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ThreePaneScaffoldPaneScope extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue> {
+  }
+
+  public enum ThreePaneScaffoldRole {
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Primary;
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Secondary;
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Tertiary;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ThreePaneScaffoldScope extends androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldScope<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue> {
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public abstract sealed class ThreePaneScaffoldState {
+    method public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getCurrentState();
+    method @FloatRange(from=0.0, to=1.0) public abstract float getProgressFraction();
+    method public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getTargetState();
+    method public abstract boolean isPredictiveBackInProgress();
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue currentState;
+    property public abstract boolean isPredictiveBackInProgress;
+    property @FloatRange(from=0.0, to=1.0) public abstract float progressFraction;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldValue implements androidx.compose.material3.adaptive.layout.PaneExpansionStateKeyProvider androidx.compose.material3.adaptive.layout.PaneScaffoldValue<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole> {
+    ctor public ThreePaneScaffoldValue(String primary, String secondary, String tertiary);
+    method public operator String get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getPaneExpansionStateKey();
+    method public String getPrimary();
+    method public String getSecondary();
+    method public String getTertiary();
+    property public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey paneExpansionStateKey;
+    property public final String primary;
+    property public final String secondary;
+    property public final String tertiary;
+  }
+
+  public final class ThreePaneScaffoldValueKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue calculateThreePaneScaffoldValue(int maxHorizontalPartitions, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends java.lang.Object?>? currentDestination);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue calculateThreePaneScaffoldValue(int maxHorizontalPartitions, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends java.lang.Object?>> destinationHistory);
+  }
+
+}
+
diff --git a/compose/material3/adaptive/adaptive-layout/api/res-1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-layout/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/api/res-1.1.0-beta01.txt
diff --git a/compose/material3/adaptive/adaptive-layout/api/restricted_1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-layout/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..b4cd5c9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,469 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive.layout {
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface AdaptStrategy {
+    method public String adapt();
+    field public static final androidx.compose.material3.adaptive.layout.AdaptStrategy.Companion Companion;
+  }
+
+  public static final class AdaptStrategy.Companion {
+    method public androidx.compose.material3.adaptive.layout.AdaptStrategy getHide();
+    property public final androidx.compose.material3.adaptive.layout.AdaptStrategy Hide;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public interface AnimatedPaneOverride {
+    method @androidx.compose.runtime.Composable public <S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> void AnimatedPane(androidx.compose.material3.adaptive.layout.AnimatedPaneOverrideContext<S,T>);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public final class AnimatedPaneOverrideContext<S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> {
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getBoundsAnimationSpec();
+    method public kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> getContent();
+    method public androidx.compose.animation.EnterTransition getEnterTransition();
+    method public androidx.compose.animation.ExitTransition getExitTransition();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T> getScope();
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> boundsAnimationSpec;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> content;
+    property public final androidx.compose.animation.EnterTransition enterTransition;
+    property public final androidx.compose.animation.ExitTransition exitTransition;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T> scope;
+  }
+
+  public sealed interface AnimatedPaneScope extends androidx.compose.animation.AnimatedVisibilityScope {
+    field public static final androidx.compose.material3.adaptive.layout.AnimatedPaneScope.Companion Companion;
+  }
+
+  public static final class AnimatedPaneScope.Companion {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public androidx.compose.material3.adaptive.layout.AnimatedPaneScope create(androidx.compose.animation.AnimatedVisibilityScope animatedVisibilityScope);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ExtendedPaneScaffoldPaneScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> extends androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldScope<Role,ScaffoldValue> androidx.compose.material3.adaptive.layout.PaneScaffoldPaneScope<Role> {
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ExtendedPaneScaffoldScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> extends androidx.compose.material3.adaptive.layout.PaneScaffoldScope androidx.compose.ui.layout.LookaheadScope androidx.compose.material3.adaptive.layout.PaneScaffoldTransitionScope<Role,ScaffoldValue> {
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class HingePolicy {
+    field public static final androidx.compose.material3.adaptive.layout.HingePolicy.Companion Companion;
+  }
+
+  public static final class HingePolicy.Companion {
+    method public int getAlwaysAvoid();
+    method public int getAvoidOccluding();
+    method public int getAvoidSeparating();
+    method public int getNeverAvoid();
+    property public final int AlwaysAvoid;
+    property public final int AvoidOccluding;
+    property public final int AvoidSeparating;
+    property public final int NeverAvoid;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ListDetailPaneScaffoldDefaults {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies(optional androidx.compose.material3.adaptive.layout.AdaptStrategy detailPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy listPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy extraPaneAdaptStrategy);
+    field public static final androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldDefaults INSTANCE;
+  }
+
+  public final class ListDetailPaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  public final class ListDetailPaneScaffoldRole {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getDetail();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getExtra();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getList();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Detail;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Extra;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole List;
+    field public static final androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public final class MutableThreePaneScaffoldState extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState {
+    ctor public MutableThreePaneScaffoldState(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue initialScaffoldValue);
+    method public suspend Object? animateTo(optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float>? animationSpec, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getCurrentState();
+    method @FloatRange(from=0.0, to=1.0) public float getProgressFraction();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getTargetState();
+    method public boolean isPredictiveBackInProgress();
+    method public suspend Object? seekTo(@FloatRange(from=0.0, to=1.0) float fraction, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState, optional boolean isPredictiveBackInProgress, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue currentState;
+    property public boolean isPredictiveBackInProgress;
+    property @FloatRange(from=0.0, to=1.0) public float progressFraction;
+    property public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState;
+  }
+
+  @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
+    field public static final androidx.compose.material3.adaptive.layout.PaneAdaptedValue.Companion Companion;
+  }
+
+  public static final class PaneAdaptedValue.Companion {
+    method public String getExpanded();
+    method public String getHidden();
+    property public final String Expanded;
+    property public final String Hidden;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public abstract sealed class PaneExpansionAnchor {
+    method @androidx.compose.runtime.Composable public abstract String getDescription();
+    property @androidx.compose.runtime.Composable public abstract String description;
+  }
+
+  public abstract static class PaneExpansionAnchor.Offset extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    method public final int getDirection();
+    method public final float getOffset();
+    property public final int direction;
+    property public final float offset;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromEnd(float offset);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset fromStart(float offset);
+  }
+
+  @kotlin.jvm.JvmInline public static final value class PaneExpansionAnchor.Offset.Direction {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor.Offset.Direction.Companion Companion;
+  }
+
+  public static final class PaneExpansionAnchor.Offset.Direction.Companion {
+    method public int getFromEnd();
+    method public int getFromStart();
+    property public final int FromEnd;
+    property public final int FromStart;
+  }
+
+  public static final class PaneExpansionAnchor.Proportion extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor {
+    ctor public PaneExpansionAnchor.Proportion(@FloatRange(from=0.0, to=1.0) float proportion);
+    method @androidx.compose.runtime.Composable public String getDescription();
+    method public float getProportion();
+    property @androidx.compose.runtime.Composable public String description;
+    property @FloatRange(from=0.0, to=1.0) public final float proportion;
+  }
+
+  public final class PaneExpansionDraggableModifierKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static kotlin.jvm.functions.Function1<androidx.compose.ui.semantics.SemanticsPropertyReceiver,kotlin.Unit> defaultDragHandleSemantics(androidx.compose.material3.adaptive.layout.PaneExpansionState);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public final class PaneExpansionState {
+    method public suspend Object? animateTo(androidx.compose.material3.adaptive.layout.PaneExpansionAnchor anchor, optional float initialVelocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void clear();
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionAnchor? getCurrentAnchor();
+    method public boolean isUnspecified();
+    method public void setFirstPaneProportion(@FloatRange(from=0.0, to=1.0) float firstPaneProportion);
+    method public void setFirstPaneWidth(int firstPaneWidth);
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionAnchor? currentAnchor;
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionState.Companion Companion;
+    field public static final int Unspecified = -1; // 0xffffffff
+  }
+
+  public static final class PaneExpansionState.Companion {
+    property public static final int Unspecified;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public sealed interface PaneExpansionStateKey {
+    field public static final androidx.compose.material3.adaptive.layout.PaneExpansionStateKey.Companion Companion;
+  }
+
+  public static final class PaneExpansionStateKey.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getDefault();
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionStateKey Default;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface PaneExpansionStateKeyProvider {
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getPaneExpansionStateKey();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneExpansionStateKey paneExpansionStateKey;
+  }
+
+  public final class PaneExpansionStateKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.layout.PaneExpansionState rememberPaneExpansionState(optional androidx.compose.material3.adaptive.layout.PaneExpansionStateKey key, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor> anchors, optional int initialAnchoredIndex, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> anchoringAnimationSpec, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.layout.PaneExpansionState rememberPaneExpansionState(androidx.compose.material3.adaptive.layout.PaneExpansionStateKeyProvider keyProvider, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.PaneExpansionAnchor> anchors, optional int initialAnchoredIndex, optional androidx.compose.animation.core.FiniteAnimationSpec<java.lang.Float> anchoringAnimationSpec, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior);
+  }
+
+  public final class PaneKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <S, T extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<S>> void AnimatedPane(androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<S,T>, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> boundsAnimationSpec, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.AnimatedPaneScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.AnimatedPaneOverride> getLocalAnimatedPaneOverride();
+    property @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.AnimatedPaneOverride> LocalAnimatedPaneOverride;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public sealed interface PaneMotion {
+    method public int getType();
+    property public abstract int type;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotion.Companion Companion;
+  }
+
+  public static final class PaneMotion.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getAnimateBounds();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromLeft();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromLeftDelayed();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromRight();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterFromRightDelayed();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getEnterWithExpand();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitToLeft();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitToRight();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getExitWithShrink();
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getNoMotion();
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion AnimateBounds;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromLeft;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromLeftDelayed;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromRight;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterFromRightDelayed;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion EnterWithExpand;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitToLeft;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitToRight;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion ExitWithShrink;
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion NoMotion;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public static final value class PaneMotion.Type {
+    method public int getValue();
+    property public final int value;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotion.Type.Companion Companion;
+  }
+
+  public static final class PaneMotion.Type.Companion {
+    method public int getEntering();
+    method public int getExiting();
+    method public int getHidden();
+    method public int getShown();
+    property public final int Entering;
+    property public final int Exiting;
+    property public final int Hidden;
+    property public final int Shown;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class PaneMotionData {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getMotion();
+    method public long getOriginPosition();
+    method public long getOriginSize();
+    method public long getTargetPosition();
+    method public long getTargetSize();
+    property public final androidx.compose.material3.adaptive.layout.PaneMotion motion;
+    property public final long originPosition;
+    property public final long originSize;
+    property public final long targetPosition;
+    property public final long targetSize;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class PaneMotionDefaults {
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> getDelayedAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> getDelayedOffsetAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> getDelayedSizeAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> getOffsetAnimationSpec();
+    method public androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> getSizeAnimationSpec();
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> AnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntRect> DelayedAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> DelayedOffsetAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> DelayedSizeAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> OffsetAnimationSpec;
+    property public final androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntSize> SizeAnimationSpec;
+    field public static final androidx.compose.material3.adaptive.layout.PaneMotionDefaults INSTANCE;
+  }
+
+  public final class PaneMotionKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static <Role> androidx.compose.animation.EnterTransition calculateDefaultEnterTransition(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, Role role);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static <Role> androidx.compose.animation.ExitTransition calculateDefaultExitTransition(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, Role role);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static inline <Role> void forEach(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, kotlin.jvm.functions.Function2<? super Role,? super androidx.compose.material3.adaptive.layout.PaneMotionData,kotlin.Unit> action);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static inline <Role> void forEachReversed(androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role>, kotlin.jvm.functions.Function2<? super Role,? super androidx.compose.material3.adaptive.layout.PaneMotionData,kotlin.Unit> action);
+  }
+
+  @androidx.compose.runtime.Immutable public final class PaneScaffoldDirective {
+    ctor public PaneScaffoldDirective(int maxHorizontalPartitions, float horizontalPartitionSpacerSize, int maxVerticalPartitions, float verticalPartitionSpacerSize, float defaultPanePreferredWidth, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective copy(optional int maxHorizontalPartitions, optional float horizontalPartitionSpacerSize, optional int maxVerticalPartitions, optional float verticalPartitionSpacerSize, optional float defaultPanePreferredWidth, optional java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public float getDefaultPanePreferredWidth();
+    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
+    method public float getHorizontalPartitionSpacerSize();
+    method public int getMaxHorizontalPartitions();
+    method public int getMaxVerticalPartitions();
+    method public float getVerticalPartitionSpacerSize();
+    property public final float defaultPanePreferredWidth;
+    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
+    property public final float horizontalPartitionSpacerSize;
+    property public final int maxHorizontalPartitions;
+    property public final int maxVerticalPartitions;
+    property public final float verticalPartitionSpacerSize;
+    field public static final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective.Companion Companion;
+  }
+
+  public static final class PaneScaffoldDirective.Companion {
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getDefault();
+    property public final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective Default;
+  }
+
+  public final class PaneScaffoldDirectiveKt {
+    method public static androidx.compose.material3.adaptive.layout.PaneScaffoldDirective calculatePaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int verticalHingePolicy);
+    method public static androidx.compose.material3.adaptive.layout.PaneScaffoldDirective calculatePaneScaffoldDirectiveWithTwoPanesOnMediumWidth(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int verticalHingePolicy);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldMotionDataProvider<Role> {
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotionData get(int index);
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotionData get(Role role);
+    method public int getCount();
+    method public Role getRoleAt(int index);
+    method public long getScaffoldSize();
+    property public abstract int count;
+    property public abstract long scaffoldSize;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldPaneScope<Role> {
+    method public androidx.compose.material3.adaptive.layout.PaneMotion getPaneMotion();
+    method public Role getPaneRole();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneMotion paneMotion;
+    property public abstract Role paneRole;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldParentData {
+    method public float getMinTouchTargetSize();
+    method public float getPreferredWidth();
+    method public boolean isAnimatedPane();
+    property public abstract boolean isAnimatedPane;
+    property public abstract float minTouchTargetSize;
+    property public abstract float preferredWidth;
+  }
+
+  public sealed interface PaneScaffoldScope {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public androidx.compose.ui.Modifier paneExpansionDraggable(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.layout.PaneExpansionState state, float minTouchTargetSize, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.ui.semantics.SemanticsPropertyReceiver,kotlin.Unit> semanticsProperties);
+    method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldTransitionScope<Role, ScaffoldValue extends androidx.compose.material3.adaptive.layout.PaneScaffoldValue<Role>> {
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role> getMotionDataProvider();
+    method @FloatRange(from=0.0, to=1.0) public float getMotionProgress();
+    method public androidx.compose.animation.core.Transition<ScaffoldValue> getScaffoldStateTransition();
+    property public abstract androidx.compose.material3.adaptive.layout.PaneScaffoldMotionDataProvider<Role> motionDataProvider;
+    property @FloatRange(from=0.0, to=1.0) public abstract float motionProgress;
+    property public abstract androidx.compose.animation.core.Transition<ScaffoldValue> scaffoldStateTransition;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface PaneScaffoldValue<T> {
+    method public operator String get(T role);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class SupportingPaneScaffoldDefaults {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies(optional androidx.compose.material3.adaptive.layout.AdaptStrategy mainPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy supportingPaneAdaptStrategy, optional androidx.compose.material3.adaptive.layout.AdaptStrategy extraPaneAdaptStrategy);
+    field public static final androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldDefaults INSTANCE;
+  }
+
+  public final class SupportingPaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.layout.PaneScaffoldDirective directive, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  public final class SupportingPaneScaffoldRole {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getExtra();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getMain();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getSupporting();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Extra;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Main;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Supporting;
+    field public static final androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneMotion {
+    method public operator androidx.compose.material3.adaptive.layout.PaneMotion get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    field public static final androidx.compose.material3.adaptive.layout.ThreePaneMotion.Companion Companion;
+  }
+
+  public static final class ThreePaneMotion.Companion {
+    method public androidx.compose.material3.adaptive.layout.ThreePaneMotion getNoMotion();
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneMotion NoMotion;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ThreePaneScaffoldAdaptStrategies {
+    ctor public ThreePaneScaffoldAdaptStrategies(androidx.compose.material3.adaptive.layout.AdaptStrategy primaryPaneAdaptStrategy, androidx.compose.material3.adaptive.layout.AdaptStrategy secondaryPaneAdaptStrategy, androidx.compose.material3.adaptive.layout.AdaptStrategy tertiaryPaneAdaptStrategy);
+    method public operator androidx.compose.material3.adaptive.layout.AdaptStrategy get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+  }
+
+  public final class ThreePaneScaffoldDestinationItem<T> {
+    ctor public ThreePaneScaffoldDestinationItem(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? contentKey);
+    method public T? getContentKey();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole getPane();
+    property public final T? contentKey;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldHorizontalOrder {
+    method public void forEach(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public void forEachIndexed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public void forEachIndexedReversed(kotlin.jvm.functions.Function2<? super java.lang.Integer,? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,kotlin.Unit> action);
+    method public operator androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole get(int index);
+    method public int getSize();
+    method public int indexOf(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    property public int size;
+  }
+
+  public final class ThreePaneScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverride> getLocalThreePaneScaffoldOverride();
+    property @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverride> LocalThreePaneScaffoldOverride;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public interface ThreePaneScaffoldOverride {
+    method @androidx.compose.runtime.Composable public void ThreePaneScaffold(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldOverrideContext);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi public final class ThreePaneScaffoldOverrideContext {
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? getPaneExpansionDragHandle();
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionState getPaneExpansionState();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder getPaneOrder();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getPrimaryPane();
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState getScaffoldState();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getSecondaryPane();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getTertiaryPane();
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle;
+    property public final androidx.compose.material3.adaptive.layout.PaneExpansionState paneExpansionState;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder paneOrder;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> primaryPane;
+    property public final androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective;
+    property public final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> secondaryPane;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? tertiaryPane;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ThreePaneScaffoldPaneScope extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldPaneScope<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue> {
+  }
+
+  public enum ThreePaneScaffoldRole {
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Primary;
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Secondary;
+    enum_constant public static final androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole Tertiary;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public sealed interface ThreePaneScaffoldScope extends androidx.compose.material3.adaptive.layout.ExtendedPaneScaffoldScope<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue> {
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public abstract sealed class ThreePaneScaffoldState {
+    method public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getCurrentState();
+    method @FloatRange(from=0.0, to=1.0) public abstract float getProgressFraction();
+    method public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getTargetState();
+    method public abstract boolean isPredictiveBackInProgress();
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue currentState;
+    property public abstract boolean isPredictiveBackInProgress;
+    property @FloatRange(from=0.0, to=1.0) public abstract float progressFraction;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue targetState;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ThreePaneScaffoldValue implements androidx.compose.material3.adaptive.layout.PaneExpansionStateKeyProvider androidx.compose.material3.adaptive.layout.PaneScaffoldValue<androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole> {
+    ctor public ThreePaneScaffoldValue(String primary, String secondary, String tertiary);
+    method public operator String get(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole role);
+    method public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey getPaneExpansionStateKey();
+    method public String getPrimary();
+    method public String getSecondary();
+    method public String getTertiary();
+    property public androidx.compose.material3.adaptive.layout.PaneExpansionStateKey paneExpansionStateKey;
+    property public final String primary;
+    property public final String secondary;
+    property public final String tertiary;
+  }
+
+  public final class ThreePaneScaffoldValueKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue calculateThreePaneScaffoldValue(int maxHorizontalPartitions, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends java.lang.Object?>? currentDestination);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue calculateThreePaneScaffoldValue(int maxHorizontalPartitions, androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends java.lang.Object?>> destinationHistory);
+  }
+
+}
+
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-af/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-af/strings.xml
new file mode 100644
index 0000000..8908ff9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-af/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Sleephandvatsel van paneeluitbreiding"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Verander paneelverdeling na %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d persent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-am/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-am/strings.xml
new file mode 100644
index 0000000..f3ec9b8
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-am/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"የፔን መዘርጋት መያዣ ይጎትቱ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ፔን መከፋፈልን ወደ %s ይለውጡ"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d መቶኛ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ar/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ar/strings.xml
new file mode 100644
index 0000000..fa48e19
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ar/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"مقبض السحب لتوسيع اللوحة"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"‏تغيير نسبة تقسيم اللوحة إلى %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"‏‫%d في المئة"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
index 120b08a..b96fec7 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-as/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"পে’ন সম্প্ৰসাৰণ কৰিবলৈ টনা হেণ্ডেল"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"পে’নৰ বিভাজন %sলৈ সলনি কৰক"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d শতাংশ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-az/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-az/strings.xml
new file mode 100644
index 0000000..4f33001
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-az/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Panelin genişləndirilməsi üçün sürükləmə tutacağı"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Panel bölgüsünü %s olaraq dəyişin"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d faiz"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-b+sr+Latn/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..b7fb312
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Marker za prevlačenje kojim se proširuje okno"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Promenite podeljeno okno na: %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Procenat: %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-be/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-be/strings.xml
new file mode 100644
index 0000000..9287ae5
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-be/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Маркер перацягвання для разгортвання панэлі"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Змяніць раздзяленне панэлі на %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d працэнтаў"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bg/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bg/strings.xml
new file mode 100644
index 0000000..9ea24d5
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bg/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Манипулатор за преместване с плъзгане за разширяване на панела"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Промяна на разделянето на панела на %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Процент: %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bn/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bn/strings.xml
new file mode 100644
index 0000000..88277ab
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"প্যানেল বড় করার টেনে আনার হ্যান্ডেল"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"প্যানেল স্প্লিট %s-এ পরিবর্তন করুন"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d শতাংশ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bs/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bs/strings.xml
new file mode 100644
index 0000000..1e37f66
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-bs/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ručica za prevlačenje radi proširenja okna"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Promjena podijeljenog okna na %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d posto"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ca/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ca/strings.xml
new file mode 100644
index 0000000..c01e276a
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ca/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ansa per arrossegar l\'expansió de la subfinestra"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Canvia la divisió de la subfinestra a %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"percentatge de %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-cs/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-cs/strings.xml
new file mode 100644
index 0000000..7b7b1f5
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-cs/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Úchyt pro přetažení a rozbalení panelu"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Změnit rozdělení panelu na %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-da/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-da/strings.xml
new file mode 100644
index 0000000..b063bfa
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-da/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Håndtag til udvidelse af rude"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Skift rudeopdeling til %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-de/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-de/strings.xml
new file mode 100644
index 0000000..1288d4d
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-de/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ziehpunkt zum Maximieren des Bereichs"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"„Fenster teilen“ in %s ändern"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d Prozent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-el/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-el/strings.xml
new file mode 100644
index 0000000..205f65d
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-el/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Λαβή μεταφοράς επέκτασης πλαισίου"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Αλλαγή επιμερισμού πλαισίου σε %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d τοις εκατό"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rAU/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..4ce37ce
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rAU/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pane expansion drag handle"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Change pane split to %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d per cent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
index c1e08b3..566041a 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rCA/strings.xml
@@ -20,4 +20,6 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pane expansion drag handle"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Change pane split to %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d percent"</string>
+    <string name="m3_adaptive_default_pane_expansion_start_offset_anchor_description" msgid="5056616348537665604">"%d DPs from start"</string>
+    <string name="m3_adaptive_default_pane_expansion_end_offset_anchor_description" msgid="6412636251656811002">"%d DPs from end"</string>
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rGB/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..4ce37ce
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rGB/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pane expansion drag handle"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Change pane split to %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d per cent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rIN/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..4ce37ce
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-en-rIN/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pane expansion drag handle"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Change pane split to %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d per cent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es-rUS/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..0b2032d
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es-rUS/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Controlador de arrastre para expandir el panel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Cambiar la división del panel a %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por ciento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es/strings.xml
new file mode 100644
index 0000000..1156a91
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-es/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Controlador de arrastre para expandir el panel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Cambiar división de panel a %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por ciento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-et/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-et/strings.xml
new file mode 100644
index 0000000..b4867e7
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-et/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Paani laiendamise lohistamispide"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Muutke jaotatud paan väärtusele %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d protsenti"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-eu/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-eu/strings.xml
new file mode 100644
index 0000000..ab819fa
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-eu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Panelaren zabalera arrastatzeko kontrol-puntua"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Aldatu panelaren zatiketa eta ezarri %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Ehuneko %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fa/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fa/strings.xml
new file mode 100644
index 0000000..b5becf3
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fa/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"دستگیره کشاندن برای از هم بازکردن اندازه قاب"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"‏تقسیم‌بندی قاب به %s تغییر کند"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"‏‫%d درصد"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fi/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fi/strings.xml
new file mode 100644
index 0000000..76852627
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fi/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ruudun laajennusvetokahva"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Muuta ruudun jaoksi %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d prosenttia"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr-rCA/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..bfcfa4f
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr-rCA/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Poignée de déplacement d\'extension du volet"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Modifiez la division du volet à %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d pour cent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr/strings.xml
new file mode 100644
index 0000000..958e4dc
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-fr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Poignée de déplacement pour développer les volets"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Passer la répartition des volets sur %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d pour cent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gl/strings.xml
new file mode 100644
index 0000000..98d43ed
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Controlador de arrastre para despregar o panel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Cambia o panel dividido a %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por cento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gu/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gu/strings.xml
new file mode 100644
index 0000000..4d0ea30
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-gu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"વિભાગ વિસ્તરણ માટે ઑબ્જેક્ટ ખેંચવાનું હૅન્ડલ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"વિભાગ વિભાજનને %s પર બદલો"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ટકા"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
index f333cf2..106bb8f 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hi/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"पैनल को बड़ा करने के लिए, खींचकर छोड़ने वाला हैंडल"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"पैनल स्प्लिट को %s में बदलें"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d प्रतिशत"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hr/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hr/strings.xml
new file mode 100644
index 0000000..011ce1e
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Marker za povlačenje proširenja okna"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Promijeni podjelu okna u: %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d posto"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hu/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hu/strings.xml
new file mode 100644
index 0000000..3c5b474
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Panel kibontásának fogópontja"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Panelfelosztás módosítása a következőre: %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d százalék"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hy/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hy/strings.xml
new file mode 100644
index 0000000..be56efd
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-hy/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Փեղկի ծավալման տեղափոխման նշիչ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Փեղկի բաժանումը դարձնել %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d տոկոս"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-in/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-in/strings.xml
new file mode 100644
index 0000000..e2015af
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-in/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Handel geser perluasan panel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Ubah luas panel ganda menjadi %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d persen"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-is/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-is/strings.xml
new file mode 100644
index 0000000..0b5b73b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-is/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Dragkló gluggastækkunar"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Breyta gluggaskiptingu í %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d prósent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-it/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-it/strings.xml
new file mode 100644
index 0000000..fd0934c
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-it/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Punto di trascinamento per l\'espansione del riquadro"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Modifica la divisione del riquadro in %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d percentuale"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-iw/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-iw/strings.xml
new file mode 100644
index 0000000..22f606e
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-iw/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"נקודת אחיזה לגרירה להרחבת החלונית"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"‏שינוי של פיצול החלונית ל-%s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"‏‫%d אחוז"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
index bfbceb0..e82e606 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ja/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ペインの展開のドラッグ ハンドル"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ペインの分割を %s に変更"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d パーセント"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
index f9f4e65..1153733 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ka/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"არეს გაფართოების სახელური ჩავლებისთვის"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"არეს გაყოფის შეცვლა %s-ით"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d პროცენტი"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kk/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kk/strings.xml
new file mode 100644
index 0000000..807f362
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Панельді жаюға арналған сүйрейтін тетік"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Панельді бөлу деңгейін %s етіп өзгерту"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d пайыз"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-km/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-km/strings.xml
new file mode 100644
index 0000000..096f5d0
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-km/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ដង​អូស​ពង្រីកផ្ទាំង"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ប្ដូរការបំបែកផ្ទាំងទៅ %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ភាគរយ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kn/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kn/strings.xml
new file mode 100644
index 0000000..585e425
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-kn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ಪೇನ್ ಅನ್ನು ವಿಸ್ತೃತಗೊಳಿಸುವುದಕ್ಕೆ ನೆರವಾಗುವ ಡ್ರ್ಯಾಗ್ ಹ್ಯಾಂಡಲ್"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ಪೇನ್ ವಿಭಜನೆಯನ್ನು %s ಗೆ ಬದಲಾಯಿಸಿ"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"ಶೇಕಡಾ %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ko/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ko/strings.xml
new file mode 100644
index 0000000..6f78f96
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ko/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"창 확장 드래그 핸들"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"창 분할을 %s(으)로 변경"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d퍼센트"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ky/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ky/strings.xml
new file mode 100644
index 0000000..dce8ec7
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ky/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Тактаны кеңейтүү үчүн сүйрөө маркери"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Тактанын бөлүнүшүн %s деп өзгөртүү"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d пайыз"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lo/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lo/strings.xml
new file mode 100644
index 0000000..c2e618f
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lo/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ບ່ອນຈັບລາກເພື່ອຂະຫຍາຍແຖບ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ປ່ຽນການແບ່ງແຖບເປັນ %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ເປີເຊັນ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lt/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lt/strings.xml
new file mode 100644
index 0000000..333a455
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lt/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Srities išplėtimo vilkimo rankenėlė"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Keisti srities skaidymą į %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d proc."</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lv/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lv/strings.xml
new file mode 100644
index 0000000..4e1a0fb
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-lv/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Rūts izvēršanas vilkšanas turis"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Mainīt rūts sadalījumu uz šādu: %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procents(-i)"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mk/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mk/strings.xml
new file mode 100644
index 0000000..51afd11
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Рачка за влечење за проширување на окното"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Променете го поделеното окно на %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d насто"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
index 2b63179c..df0ae0a 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ml/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"പെയിൻ വികസിപ്പിക്കാനായി വലിച്ചിടുന്നതിനുള്ള ഹാൻഡിൽ"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"പെയിൻ വിഭജനം %s ആയി മാറ്റുക"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ശതമാനം"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mn/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mn/strings.xml
new file mode 100644
index 0000000..3ccb872
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mn/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Хэсгийн өргөтгөлийг чирэх бариул"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Хэсгийн хуваалтыг %s болгож өөрчлөх"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d хувь"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mr/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mr/strings.xml
new file mode 100644
index 0000000..7579a02
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-mr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"पेन विस्तार ड्रॅग हँडल"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"स्प्लिट पेन %s वर बदला"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d टक्के"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
index 889db66e..ad90a10 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ms/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Pemegang seret pengembangan anak tetingkap"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Tukar anak tetingkap terpisah kepada %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d peratus"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-my/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-my/strings.xml
new file mode 100644
index 0000000..0b33798
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-my/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"အကန့်တိုးချဲ့မှု ဖိဆွဲအထိန်း"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"အကန့်အခွဲကို %s သို့ ပြောင်းနိုင်သည်"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ရာခိုင်နှုန်း"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nb/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nb/strings.xml
new file mode 100644
index 0000000..c2b4ce3
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nb/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Håndtak for utvidelse av feltet"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Endre feltdelingen til %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d prosent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ne/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ne/strings.xml
new file mode 100644
index 0000000..b0560f5
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ne/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"पेन एक्स्पान्सनको ड्र्याग ह्यान्डल"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"पेन स्प्लिट परिवर्तन गरी %s बनाउनुहोस्"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d प्रतिशत"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nl/strings.xml
new file mode 100644
index 0000000..82a9d5c
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-nl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Handgreep voor slepen om deelvenster uit te breiden"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Deelvenstersplitsing wijzigen in %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-or/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-or/strings.xml
new file mode 100644
index 0000000..f84b2f5
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-or/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ପେନ ବିସ୍ତାର ଡ୍ରାଗ ହେଣ୍ଡେଲ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ପେନ ସ୍ପ୍ଲିଟକୁ %sରେ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ଶତକଡ଼ା"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pa/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pa/strings.xml
new file mode 100644
index 0000000..d139af9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pa/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"ਪੂਰਵ-ਝਲਕ ਦਾ ਵਿਸਤਾਰ ਕਰਨ ਲਈ ਘਸੀਟਣ ਵਾਲਾ ਹੈਂਡਲ"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"ਸਪਲਿਟ ਪੂਰਵ-ਝਲਕ ਨੂੰ %s \'ਤੇ ਬਦਲੋ"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d ਫ਼ੀਸਦ"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
index ec85843..d9f3cd1 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pl/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Uchwyt do przeciągania panelu"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Zmień podział panelu na %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rBR/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..740a3f9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rBR/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Alça de arrastar para expandir o painel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Mudar a divisão do painel para %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por cento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
index 115f3c0..96cd773 100644
--- a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt-rPT/strings.xml
@@ -20,4 +20,8 @@
     <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Indicador para arrastar de expansão do painel"</string>
     <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Altere a divisão do painel para %s"</string>
     <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por cento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
 </resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt/strings.xml
new file mode 100644
index 0000000..740a3f9
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-pt/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Alça de arrastar para expandir o painel"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Mudar a divisão do painel para %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d por cento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ro/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ro/strings.xml
new file mode 100644
index 0000000..8c1397e
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ro/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ghidaj de tragere pentru extinderea panoului"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Modifică împărțirea panoului la %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ru/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ru/strings.xml
new file mode 100644
index 0000000..d04f3ca
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ru/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Маркер перемещения для расширения панели"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Изменить пропорцию разделения панелей на %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Значение в процентах: %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-si/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-si/strings.xml
new file mode 100644
index 0000000..1c5a14a1
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-si/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"පැනල ප්‍රසාරණ ඇදීම් හැඬලය"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"කවුළු බෙදීම %s ලෙස වෙනස් කරන්න"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"සියයට %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sk/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sk/strings.xml
new file mode 100644
index 0000000..1bcb79a
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Presúvadlo na rozšírenie panela"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Zmeniť rozdelenie panela na %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Počet percent: %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sl/strings.xml
new file mode 100644
index 0000000..c7ca0b6
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Ročica za vlečenje za razširitev podokna"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Sprememba razdelitve podokna na %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d odstotkov"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sq/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sq/strings.xml
new file mode 100644
index 0000000..27b0a73
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sq/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Doreza e zvarritjes për zgjerimin e panelit"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Ndrysho ndarjen e panelit në %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d për qind"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sr/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sr/strings.xml
new file mode 100644
index 0000000..8c51385
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Маркер за превлачење којим се проширује окно"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Промените подељено окно на: %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Проценат: %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sv/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sv/strings.xml
new file mode 100644
index 0000000..010c964
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sv/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Handtag för rutexpansion"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Ändra rutdelning till %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d procent"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sw/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sw/strings.xml
new file mode 100644
index 0000000..06d401c
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-sw/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Aikoni ya buruta ili kupanua kijisehemu"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Badilisha hali ya kugawanya kijisehemu iwe %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Asilimia %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ta/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ta/strings.xml
new file mode 100644
index 0000000..dfc1028
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ta/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"பெட்டியை இழுத்து விரிவாக்குவதற்கான ஹேண்டில்"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"பெட்டிப் பிரித்தலை %s ஆக மாற்றும்"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d சதவீதம்"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-te/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-te/strings.xml
new file mode 100644
index 0000000..63c702b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-te/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"పేన్‌ను విస్తరించడానికి లాగే హ్యాండిల్"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"పేన్ విభజనను %s‌కు మార్చండి"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d శాతం"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-th/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-th/strings.xml
new file mode 100644
index 0000000..94ce1e8
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-th/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"แฮนเดิลการลากเพื่อขยายแผง"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"เปลี่ยนการแบ่งแผงเป็น %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d เปอร์เซ็นต์"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tl/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tl/strings.xml
new file mode 100644
index 0000000..b459c2a
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tl/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Handle sa pag-drag sa pagpapalawak ng pane"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Gawing %s ang pane split"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d (na) porsyento"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tr/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tr/strings.xml
new file mode 100644
index 0000000..d478356
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-tr/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Bölmeyi genişletmek için sürükleme tutamacı"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Bölme oranını %s olarak değiştirin"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"Yüzde %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uk/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uk/strings.xml
new file mode 100644
index 0000000..27680e2b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uk/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Маркер переміщення для розгортання панелі"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Змінити розділення панелі на %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d%%"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ur/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ur/strings.xml
new file mode 100644
index 0000000..3acbaeeb
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-ur/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"پین کو پھیلانے کے لیے گھسیٹنے کا ہینڈل"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"‏پین اسپلٹ کو ‎%s میں تبدیل کریں"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"‏‎%d فیصد"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uz/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uz/strings.xml
new file mode 100644
index 0000000..36d8660
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-uz/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Panelni kengaytirish uchun surish dastagi"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Ajratilgan panelni %s sifatida oʻzgartirish"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d foiz"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-vi/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-vi/strings.xml
new file mode 100644
index 0000000..e5cf8f1
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-vi/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Nút kéo mở rộng ngăn"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Thay đổi chế độ tách ngăn thành %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d phần trăm"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rCN/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..671e560
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rCN/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"窗格展开拖动手柄"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"将窗格分割更改为%s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"百分之 %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rHK/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..6309aa1
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rHK/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"展開窗格拖曳控點"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"將分割窗格轉做 %s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"百分之 %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rTW/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..4da1690
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zh-rTW/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"窗格擴展拖曳控點"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"將窗格分割變更為「%s」"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"百分之 %d"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zu/strings.xml b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zu/strings.xml
new file mode 100644
index 0000000..c549752
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-layout/src/androidMain/res/values-zu/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright 2025 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       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.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_content_description" msgid="9058489142432490820">"Isibambo sokuhudula isandiso sepane"</string>
+    <string name="m3_adaptive_default_pane_expansion_drag_handle_action_description" msgid="9031621431415014327">"Shintsha ukuhlukana kwepane kube ku-%s"</string>
+    <string name="m3_adaptive_default_pane_expansion_proportion_anchor_description" msgid="1205294531112795522">"%d iphesenti"</string>
+    <!-- no translation found for m3_adaptive_default_pane_expansion_start_offset_anchor_description (5056616348537665604) -->
+    <skip />
+    <!-- no translation found for m3_adaptive_default_pane_expansion_end_offset_anchor_description (6412636251656811002) -->
+    <skip />
+</resources>
diff --git a/compose/material3/adaptive/adaptive-navigation/api/1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-navigation/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..ba0712b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-navigation/api/1.1.0-beta01.txt
@@ -0,0 +1,55 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive.navigation {
+
+  public final class AndroidThreePaneScaffold_androidKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+    field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+  }
+
+  public static final class BackNavigationBehavior.Companion {
+    method public String getPopLatest();
+    method public String getPopUntilContentChange();
+    method public String getPopUntilCurrentDestinationChange();
+    method public String getPopUntilScaffoldValueChange();
+    property public final String PopLatest;
+    property public final String PopUntilContentChange;
+    property public final String PopUntilCurrentDestinationChange;
+    property public final String PopUntilScaffoldValueChange;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
+    method public boolean canNavigateBack(optional String backNavigationBehavior);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState getScaffoldState();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
+    method public boolean isDestinationHistoryAware();
+    method public suspend Object? navigateBack(optional String backNavigationBehavior, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+    method public suspend Object? navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? contentKey, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue peekPreviousScaffoldValue(optional String backNavigationBehavior);
+    method public suspend Object? seekBack(optional String backNavigationBehavior, optional @FloatRange(from=0.0, to=1.0) float fraction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void setDestinationHistoryAware(boolean);
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
+    property public abstract boolean isDestinationHistoryAware;
+    property public abstract androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue scaffoldValue;
+  }
+
+  public final class ThreePaneScaffoldNavigatorKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> rememberListDetailPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> rememberListDetailPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends T>> initialDestinationHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> rememberSupportingPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> rememberSupportingPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends T>> initialDestinationHistory);
+  }
+
+  public final class ThreePaneScaffoldPredictiveBackHandler_androidKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void ThreePaneScaffoldPredictiveBackHandler(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, String backBehavior);
+  }
+
+}
+
diff --git a/compose/material3/adaptive/adaptive-navigation/api/res-1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-navigation/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-navigation/api/res-1.1.0-beta01.txt
diff --git a/compose/material3/adaptive/adaptive-navigation/api/restricted_1.1.0-beta01.txt b/compose/material3/adaptive/adaptive-navigation/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..ba0712b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive-navigation/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,55 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive.navigation {
+
+  public final class AndroidThreePaneScaffold_androidKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void NavigableListDetailPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> listPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> detailPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void NavigableSupportingPaneScaffold(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> mainPane, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope,kotlin.Unit>? extraPane, optional String defaultBackBehavior, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.layout.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Unit>? paneExpansionDragHandle, optional androidx.compose.material3.adaptive.layout.PaneExpansionState? paneExpansionState);
+  }
+
+  @kotlin.jvm.JvmInline public final value class BackNavigationBehavior {
+    field public static final androidx.compose.material3.adaptive.navigation.BackNavigationBehavior.Companion Companion;
+  }
+
+  public static final class BackNavigationBehavior.Companion {
+    method public String getPopLatest();
+    method public String getPopUntilContentChange();
+    method public String getPopUntilCurrentDestinationChange();
+    method public String getPopUntilScaffoldValueChange();
+    property public final String PopLatest;
+    property public final String PopUntilContentChange;
+    property public final String PopUntilCurrentDestinationChange;
+    property public final String PopUntilScaffoldValueChange;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ThreePaneScaffoldNavigator<T> {
+    method public boolean canNavigateBack(optional String backNavigationBehavior);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? getCurrentDestination();
+    method public androidx.compose.material3.adaptive.layout.PaneScaffoldDirective getScaffoldDirective();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState getScaffoldState();
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue getScaffoldValue();
+    method public boolean isDestinationHistoryAware();
+    method public suspend Object? navigateBack(optional String backNavigationBehavior, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+    method public suspend Object? navigateTo(androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole pane, optional T? contentKey, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue peekPreviousScaffoldValue(optional String backNavigationBehavior);
+    method public suspend Object? seekBack(optional String backNavigationBehavior, optional @FloatRange(from=0.0, to=1.0) float fraction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void setDestinationHistoryAware(boolean);
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<T>? currentDestination;
+    property public abstract boolean isDestinationHistoryAware;
+    property public abstract androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldState scaffoldState;
+    property public abstract androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue scaffoldValue;
+  }
+
+  public final class ThreePaneScaffoldNavigatorKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> rememberListDetailPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> rememberListDetailPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends T>> initialDestinationHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<java.lang.Object> rememberSupportingPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> rememberSupportingPaneScaffoldNavigator(optional androidx.compose.material3.adaptive.layout.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.layout.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional boolean isDestinationHistoryAware, optional java.util.List<? extends androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem<? extends T>> initialDestinationHistory);
+  }
+
+  public final class ThreePaneScaffoldPredictiveBackHandler_androidKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static <T> void ThreePaneScaffoldPredictiveBackHandler(androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator<T> navigator, String backBehavior);
+  }
+
+}
+
diff --git a/compose/material3/adaptive/adaptive/api/1.1.0-beta01.txt b/compose/material3/adaptive/adaptive/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..a93216b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive/api/1.1.0-beta01.txt
@@ -0,0 +1,62 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive {
+
+  public final class AndroidPosture_androidKt {
+    method public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
+  }
+
+  public final class AndroidWindowAdaptiveInfo_androidKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.util.List<androidx.window.layout.FoldingFeature>> collectFoldingFeaturesAsState();
+    method @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.WindowAdaptiveInfo currentWindowAdaptiveInfo();
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static long currentWindowDpSize();
+    method @androidx.compose.runtime.Composable public static long currentWindowSize();
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3 adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveApi {
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3 adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveComponentOverrideApi {
+  }
+
+  @androidx.compose.runtime.Immutable public final class HingeInfo {
+    ctor public HingeInfo(androidx.compose.ui.geometry.Rect bounds, boolean isFlat, boolean isVertical, boolean isSeparating, boolean isOccluding);
+    method public androidx.compose.ui.geometry.Rect getBounds();
+    method public boolean isFlat();
+    method public boolean isOccluding();
+    method public boolean isSeparating();
+    method public boolean isVertical();
+    property public final androidx.compose.ui.geometry.Rect bounds;
+    property public final boolean isFlat;
+    property public final boolean isOccluding;
+    property public final boolean isSeparating;
+    property public final boolean isVertical;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Posture {
+    ctor public Posture();
+    ctor public Posture(optional boolean isTabletop, optional java.util.List<androidx.compose.material3.adaptive.HingeInfo> hingeList);
+    method public java.util.List<androidx.compose.material3.adaptive.HingeInfo> getHingeList();
+    method public boolean isTabletop();
+    property public final java.util.List<androidx.compose.material3.adaptive.HingeInfo> hingeList;
+    property public final boolean isTabletop;
+  }
+
+  public final class PostureKt {
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getAllHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getAllVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getOccludingHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getOccludingVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getSeparatingHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getSeparatingVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+  }
+
+  @androidx.compose.runtime.Immutable public final class WindowAdaptiveInfo {
+    ctor public WindowAdaptiveInfo(androidx.window.core.layout.WindowSizeClass windowSizeClass, androidx.compose.material3.adaptive.Posture windowPosture);
+    method public androidx.compose.material3.adaptive.Posture getWindowPosture();
+    method public androidx.window.core.layout.WindowSizeClass getWindowSizeClass();
+    property public final androidx.compose.material3.adaptive.Posture windowPosture;
+    property public final androidx.window.core.layout.WindowSizeClass windowSizeClass;
+  }
+
+}
+
diff --git a/compose/material3/adaptive/adaptive/api/res-1.1.0-beta01.txt b/compose/material3/adaptive/adaptive/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/adaptive/adaptive/api/res-1.1.0-beta01.txt
diff --git a/compose/material3/adaptive/adaptive/api/restricted_1.1.0-beta01.txt b/compose/material3/adaptive/adaptive/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..a93216b
--- /dev/null
+++ b/compose/material3/adaptive/adaptive/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,62 @@
+// Signature format: 4.0
+package androidx.compose.material3.adaptive {
+
+  public final class AndroidPosture_androidKt {
+    method public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
+  }
+
+  public final class AndroidWindowAdaptiveInfo_androidKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.util.List<androidx.window.layout.FoldingFeature>> collectFoldingFeaturesAsState();
+    method @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.WindowAdaptiveInfo currentWindowAdaptiveInfo();
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static long currentWindowDpSize();
+    method @androidx.compose.runtime.Composable public static long currentWindowSize();
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3 adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveApi {
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="This material3 adaptive API is experimental and is likely to change or to be" + "removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3AdaptiveComponentOverrideApi {
+  }
+
+  @androidx.compose.runtime.Immutable public final class HingeInfo {
+    ctor public HingeInfo(androidx.compose.ui.geometry.Rect bounds, boolean isFlat, boolean isVertical, boolean isSeparating, boolean isOccluding);
+    method public androidx.compose.ui.geometry.Rect getBounds();
+    method public boolean isFlat();
+    method public boolean isOccluding();
+    method public boolean isSeparating();
+    method public boolean isVertical();
+    property public final androidx.compose.ui.geometry.Rect bounds;
+    property public final boolean isFlat;
+    property public final boolean isOccluding;
+    property public final boolean isSeparating;
+    property public final boolean isVertical;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Posture {
+    ctor public Posture();
+    ctor public Posture(optional boolean isTabletop, optional java.util.List<androidx.compose.material3.adaptive.HingeInfo> hingeList);
+    method public java.util.List<androidx.compose.material3.adaptive.HingeInfo> getHingeList();
+    method public boolean isTabletop();
+    property public final java.util.List<androidx.compose.material3.adaptive.HingeInfo> hingeList;
+    property public final boolean isTabletop;
+  }
+
+  public final class PostureKt {
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getAllHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getAllVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getOccludingHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getOccludingVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getSeparatingHorizontalHingeBounds(androidx.compose.material3.adaptive.Posture);
+    method public static java.util.List<androidx.compose.ui.geometry.Rect> getSeparatingVerticalHingeBounds(androidx.compose.material3.adaptive.Posture);
+  }
+
+  @androidx.compose.runtime.Immutable public final class WindowAdaptiveInfo {
+    ctor public WindowAdaptiveInfo(androidx.window.core.layout.WindowSizeClass windowSizeClass, androidx.compose.material3.adaptive.Posture windowPosture);
+    method public androidx.compose.material3.adaptive.Posture getWindowPosture();
+    method public androidx.window.core.layout.WindowSizeClass getWindowSizeClass();
+    property public final androidx.compose.material3.adaptive.Posture windowPosture;
+    property public final androidx.window.core.layout.WindowSizeClass windowSizeClass;
+  }
+
+}
+
diff --git a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/BottomAppBarBenchmark.kt b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/BottomAppBarBenchmark.kt
index 96f3a4c..a589092 100644
--- a/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/BottomAppBarBenchmark.kt
+++ b/compose/material3/benchmark/src/androidTest/java/androidx/compose/material3/benchmark/BottomAppBarBenchmark.kt
@@ -21,7 +21,6 @@
 import androidx.compose.material.icons.automirrored.filled.ArrowBack
 import androidx.compose.material.icons.automirrored.filled.ArrowForward
 import androidx.compose.material3.BottomAppBar
-import androidx.compose.material3.BottomAppBarDefaults
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.Icon
@@ -80,7 +79,6 @@
     @Composable
     override fun MeasuredContent() {
         BottomAppBar(
-            horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
             modifier = Modifier.fillMaxWidth(),
         ) {
             IconButton(onClick = { /* doSomething() */ }) {
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 273f29f..b4c8ef0 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -34,7 +34,6 @@
   }
 
   public final class AppBarKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void BottomAppBar(androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
@@ -42,6 +41,7 @@
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void FlexibleBottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void LargeFlexibleTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Alignment.Horizontal titleHorizontalAlignment, optional float collapsedHeight, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional float collapsedHeight, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
@@ -91,11 +91,17 @@
     method @androidx.compose.runtime.Composable public long getContainerColor();
     method public float getContainerElevation();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
-    method public androidx.compose.foundation.layout.Arrangement.Horizontal getHorizontalArrangement();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public float getFlexibleBottomAppBarHeight();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.PaddingValues getFlexibleContentPadding();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.Arrangement.Horizontal getFlexibleFixedHorizontalArrangement();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.Arrangement.Horizontal getFlexibleHorizontalArrangement();
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
     property public final float ContainerElevation;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
-    property public final androidx.compose.foundation.layout.Arrangement.Horizontal HorizontalArrangement;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final float FlexibleBottomAppBarHeight;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.PaddingValues FlexibleContentPadding;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.Arrangement.Horizontal FlexibleFixedHorizontalArrangement;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.Arrangement.Horizontal FlexibleHorizontalArrangement;
     property @androidx.compose.runtime.Composable public final long bottomAppBarFabColor;
     property @androidx.compose.runtime.Composable public final long containerColor;
     property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
@@ -396,11 +402,15 @@
   public final class CheckboxDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+    method public float getStrokeWidth();
+    property public final float StrokeWidth;
     field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
   }
 
   public final class CheckboxKt {
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void Checkbox(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.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 273f29f..b4c8ef0 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -34,7 +34,6 @@
   }
 
   public final class AppBarKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void BottomAppBar(androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable public static void BottomAppBar(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? floatingActionButton, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets);
@@ -42,6 +41,7 @@
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.BottomAppBarState BottomAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void CenterAlignedTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void FlexibleBottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.Arrangement.Horizontal horizontalArrangement, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.BottomAppBarScrollBehavior? scrollBehavior, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public static void LargeFlexibleTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.ui.Alignment.Horizontal titleHorizontalAlignment, optional float collapsedHeight, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void LargeTopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional float collapsedHeight, optional float expandedHeight, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.material3.TopAppBarColors colors, optional androidx.compose.material3.TopAppBarScrollBehavior? scrollBehavior);
@@ -91,11 +91,17 @@
     method @androidx.compose.runtime.Composable public long getContainerColor();
     method public float getContainerElevation();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
-    method public androidx.compose.foundation.layout.Arrangement.Horizontal getHorizontalArrangement();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public float getFlexibleBottomAppBarHeight();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.PaddingValues getFlexibleContentPadding();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.Arrangement.Horizontal getFlexibleFixedHorizontalArrangement();
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public androidx.compose.foundation.layout.Arrangement.Horizontal getFlexibleHorizontalArrangement();
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
     property public final float ContainerElevation;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
-    property public final androidx.compose.foundation.layout.Arrangement.Horizontal HorizontalArrangement;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final float FlexibleBottomAppBarHeight;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.PaddingValues FlexibleContentPadding;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.Arrangement.Horizontal FlexibleFixedHorizontalArrangement;
+    property @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public final androidx.compose.foundation.layout.Arrangement.Horizontal FlexibleHorizontalArrangement;
     property @androidx.compose.runtime.Composable public final long bottomAppBarFabColor;
     property @androidx.compose.runtime.Composable public final long containerColor;
     property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
@@ -396,11 +402,15 @@
   public final class CheckboxDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.CheckboxColors colors(optional long checkedColor, optional long uncheckedColor, optional long checkmarkColor, optional long disabledCheckedColor, optional long disabledUncheckedColor, optional long disabledIndeterminateColor);
+    method public float getStrokeWidth();
+    property public final float StrokeWidth;
     field public static final androidx.compose.material3.CheckboxDefaults INSTANCE;
   }
 
   public final class CheckboxKt {
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void Checkbox(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.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, androidx.compose.ui.graphics.drawscope.Stroke checkmarkStroke, androidx.compose.ui.graphics.drawscope.Stroke outlineStroke, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
     method @androidx.compose.runtime.Composable public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
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 6ab1a76..16faf52 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
@@ -43,6 +43,7 @@
 import androidx.compose.material3.samples.CardSample
 import androidx.compose.material3.samples.CenteredHorizontalFloatingToolbarWithFabSample
 import androidx.compose.material3.samples.CenteredVerticalFloatingToolbarWithFabSample
+import androidx.compose.material3.samples.CheckboxRoundedStrokesSample
 import androidx.compose.material3.samples.CheckboxSample
 import androidx.compose.material3.samples.CheckboxWithTextSample
 import androidx.compose.material3.samples.ChipGroupReflowSample
@@ -248,6 +249,7 @@
 import androidx.compose.material3.samples.ToggleButtonWithIconSample
 import androidx.compose.material3.samples.TonalSplitButtonSample
 import androidx.compose.material3.samples.TonalToggleButtonSample
+import androidx.compose.material3.samples.TriStateCheckboxRoundedStrokesSample
 import androidx.compose.material3.samples.TriStateCheckboxSample
 import androidx.compose.material3.samples.TwoLineListItem
 import androidx.compose.material3.samples.VerticalFloatingToolbarWithFabSample
@@ -585,12 +587,26 @@
             CheckboxWithTextSample()
         },
         Example(
+            name = "CheckboxRoundedStrokesSample",
+            description = CheckboxesExampleDescription,
+            sourceUrl = CheckboxesExampleSourceUrl
+        ) {
+            CheckboxRoundedStrokesSample()
+        },
+        Example(
             name = "TriStateCheckboxSample",
             description = CheckboxesExampleDescription,
             sourceUrl = CheckboxesExampleSourceUrl
         ) {
             TriStateCheckboxSample()
-        }
+        },
+        Example(
+            name = "TriStateCheckboxRoundedStrokesSample",
+            description = CheckboxesExampleDescription,
+            sourceUrl = CheckboxesExampleSourceUrl
+        ) {
+            TriStateCheckboxRoundedStrokesSample()
+        },
     )
 
 private const val ChipsExampleDescription = "Chips examples"
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
index 3c08716..1986cce 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/AppBarSamples.kt
@@ -44,6 +44,7 @@
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.FabPosition
 import androidx.compose.material3.FilledIconButton
+import androidx.compose.material3.FlexibleBottomAppBar
 import androidx.compose.material3.FloatingActionButton
 import androidx.compose.material3.FloatingActionButtonDefaults
 import androidx.compose.material3.Icon
@@ -784,8 +785,8 @@
 }
 
 /**
- * A sample for a [BottomAppBar] that collapses when the content is scrolled up, and appears when
- * the content scrolled down. The content is spaced around.
+ * A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
+ * when the content scrolled down. The content is spaced around.
  */
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Preview
@@ -801,7 +802,7 @@
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         bottomBar = {
-            BottomAppBar(
+            FlexibleBottomAppBar(
                 horizontalArrangement = Arrangement.SpaceAround,
                 contentPadding = PaddingValues(horizontal = 0.dp),
                 scrollBehavior = if (!isTouchExplorationEnabled) scrollBehavior else null,
@@ -852,8 +853,8 @@
 }
 
 /**
- * A sample for a [BottomAppBar] that collapses when the content is scrolled up, and appears when
- * the content scrolled down. The content is spaced between.
+ * A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
+ * when the content scrolled down. The content is spaced between.
  */
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Preview
@@ -869,7 +870,7 @@
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         bottomBar = {
-            BottomAppBar(
+            FlexibleBottomAppBar(
                 horizontalArrangement = Arrangement.SpaceBetween,
                 scrollBehavior = if (!isTouchExplorationEnabled) scrollBehavior else null,
                 content = {
@@ -919,8 +920,8 @@
 }
 
 /**
- * A sample for a [BottomAppBar] that collapses when the content is scrolled up, and appears when
- * the content scrolled down. The content is spaced evenly.
+ * A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
+ * when the content scrolled down. The content is spaced evenly.
  */
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Preview
@@ -936,7 +937,7 @@
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         bottomBar = {
-            BottomAppBar(
+            FlexibleBottomAppBar(
                 horizontalArrangement = Arrangement.SpaceEvenly,
                 contentPadding = PaddingValues(horizontal = 0.dp),
                 scrollBehavior = if (!isTouchExplorationEnabled) scrollBehavior else null,
@@ -987,8 +988,8 @@
 }
 
 /**
- * A sample for a [BottomAppBar] that collapses when the content is scrolled up, and appears when
- * the content scrolled down. The content arrangement is fixed.
+ * A sample for a [FlexibleBottomAppBar] that collapses when the content is scrolled up, and appears
+ * when the content scrolled down. The content arrangement is fixed.
  */
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Preview
@@ -1004,8 +1005,8 @@
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         bottomBar = {
-            BottomAppBar(
-                horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
+            FlexibleBottomAppBar(
+                horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
                 scrollBehavior = if (!isTouchExplorationEnabled) scrollBehavior else null,
                 content = {
                     IconButton(onClick = { /* doSomething() */ }) {
@@ -1054,8 +1055,8 @@
 }
 
 /**
- * A sample for a vibrant [BottomAppBar] that collapses when the content is scrolled up, and appears
- * when the content scrolled down. The content arrangement is fixed.
+ * A sample for a vibrant [FlexibleBottomAppBar] that collapses when the content is scrolled up, and
+ * appears when the content scrolled down. The content arrangement is fixed.
  */
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
 @Preview
@@ -1071,8 +1072,8 @@
     Scaffold(
         modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
         bottomBar = {
-            BottomAppBar(
-                horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
+            FlexibleBottomAppBar(
+                horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
                 scrollBehavior = if (!isTouchExplorationEnabled) scrollBehavior else null,
                 containerColor =
                     MaterialTheme.colorScheme.primaryContainer, // TODO(b/356885344): tokens
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
index c15860d..61d6130 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/CheckboxSamples.kt
@@ -27,6 +27,7 @@
 import androidx.compose.foundation.selection.toggleable
 import androidx.compose.foundation.selection.triStateToggleable
 import androidx.compose.material3.Checkbox
+import androidx.compose.material3.CheckboxDefaults
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.material3.TriStateCheckbox
@@ -35,10 +36,15 @@
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import kotlin.math.floor
 
 @Preview
 @Sampled
@@ -79,6 +85,29 @@
 @Preview
 @Sampled
 @Composable
+fun CheckboxRoundedStrokesSample() {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    val checkmarkStroke =
+        remember(strokeWidthPx) {
+            Stroke(
+                width = strokeWidthPx,
+                cap = StrokeCap.Round,
+                join = StrokeJoin.Round,
+            )
+        }
+    val outlineStroke = remember(strokeWidthPx) { Stroke(width = strokeWidthPx) }
+    val checkedState = remember { mutableStateOf(true) }
+    Checkbox(
+        checked = checkedState.value,
+        onCheckedChange = { checkedState.value = it },
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke
+    )
+}
+
+@Preview
+@Sampled
+@Composable
 fun TriStateCheckboxSample() {
     Column {
         // define dependent checkboxes states
@@ -146,3 +175,96 @@
         }
     }
 }
+
+@Preview
+@Sampled
+@Composable
+fun TriStateCheckboxRoundedStrokesSample() {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    val checkmarkStroke =
+        remember(strokeWidthPx) {
+            Stroke(
+                width = strokeWidthPx,
+                cap = StrokeCap.Round,
+                join = StrokeJoin.Round,
+            )
+        }
+    val outlineStroke = remember(strokeWidthPx) { Stroke(width = strokeWidthPx) }
+    Column {
+        // define dependent checkboxes states
+        val (state, onStateChange) = remember { mutableStateOf(true) }
+        val (state2, onStateChange2) = remember { mutableStateOf(true) }
+
+        // TriStateCheckbox state reflects state of dependent checkboxes
+        val parentState =
+            remember(state, state2) {
+                if (state && state2) ToggleableState.On
+                else if (!state && !state2) ToggleableState.Off else ToggleableState.Indeterminate
+            }
+        // click on TriStateCheckbox can set state for dependent checkboxes
+        val onParentClick = {
+            val s = parentState != ToggleableState.On
+            onStateChange(s)
+            onStateChange2(s)
+        }
+
+        // The sample below composes just basic checkboxes which are not fully accessible on their
+        // own. See the CheckboxWithTextSample as a way to ensure your checkboxes are fully
+        // accessible.
+        Row(
+            verticalAlignment = Alignment.CenterVertically,
+            modifier =
+                Modifier.triStateToggleable(
+                    state = parentState,
+                    onClick = onParentClick,
+                    role = Role.Checkbox
+                )
+        ) {
+            TriStateCheckbox(
+                state = parentState,
+                onClick = null,
+                checkmarkStroke = checkmarkStroke,
+                outlineStroke = outlineStroke
+            )
+            Text("Receive Emails")
+        }
+        Spacer(Modifier.size(25.dp))
+        Column(Modifier.padding(24.dp, 0.dp, 0.dp, 0.dp)) {
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier =
+                    Modifier.toggleable(
+                        value = state,
+                        onValueChange = onStateChange,
+                        role = Role.Checkbox
+                    )
+            ) {
+                Checkbox(
+                    checked = state,
+                    onCheckedChange = null,
+                    checkmarkStroke = checkmarkStroke,
+                    outlineStroke = outlineStroke
+                )
+                Text("Daily")
+            }
+            Spacer(Modifier.size(25.dp))
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier =
+                    Modifier.toggleable(
+                        value = state2,
+                        onValueChange = onStateChange2,
+                        role = Role.Checkbox
+                    )
+            ) {
+                Checkbox(
+                    checked = state2,
+                    onCheckedChange = null,
+                    checkmarkStroke = checkmarkStroke,
+                    outlineStroke = outlineStroke
+                )
+                Text("Weekly")
+            }
+        }
+    }
+}
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
index 1a9d7b6..4b0b977 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarScreenshotTest.kt
@@ -657,7 +657,7 @@
     fun bottomAppBarSpacedAround_lightTheme() {
         composeTestRule.setMaterialContent(lightColorScheme()) {
             Box(Modifier.testTag(BottomAppBarTestTag)) {
-                BottomAppBar(
+                FlexibleBottomAppBar(
                     horizontalArrangement = Arrangement.SpaceAround,
                     contentPadding = PaddingValues(horizontal = 0.dp),
                     content = {
@@ -700,8 +700,9 @@
     fun bottomAppBarSpacedBetween_lightTheme() {
         composeTestRule.setMaterialContent(lightColorScheme()) {
             Box(Modifier.testTag(BottomAppBarTestTag)) {
-                BottomAppBar(
-                    horizontalArrangement = Arrangement.SpaceBetween,
+                FlexibleBottomAppBar(
+                    // The default BottomAppBarDefaults.FlexibleHorizontalArrangement is an
+                    // Arrangement.SpacedBetween.
                     content = {
                         IconButton(onClick = { /* doSomething() */ }) {
                             Icon(
@@ -742,7 +743,7 @@
     fun bottomAppBarSpacedEvenly_lightTheme() {
         composeTestRule.setMaterialContent(lightColorScheme()) {
             Box(Modifier.testTag(BottomAppBarTestTag)) {
-                BottomAppBar(
+                FlexibleBottomAppBar(
                     horizontalArrangement = Arrangement.SpaceEvenly,
                     contentPadding = PaddingValues(horizontal = 0.dp),
                     content = {
@@ -785,8 +786,8 @@
     fun bottomAppBarFixed_lightTheme() {
         composeTestRule.setMaterialContent(lightColorScheme()) {
             Box(Modifier.testTag(BottomAppBarTestTag)) {
-                BottomAppBar(
-                    horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
+                FlexibleBottomAppBar(
+                    horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
                     content = {
                         IconButton(onClick = { /* doSomething() */ }) {
                             Icon(
@@ -827,8 +828,8 @@
     fun bottomAppBarFixed_darkTheme() {
         composeTestRule.setMaterialContent(darkColorScheme()) {
             Box(Modifier.testTag(BottomAppBarTestTag)) {
-                BottomAppBar(
-                    horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
+                FlexibleBottomAppBar(
+                    horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
                     content = {
                         IconButton(onClick = { /* doSomething() */ }) {
                             Icon(
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarTest.kt
index 71612d1..94eb5d0 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AppBarTest.kt
@@ -1852,12 +1852,27 @@
     fun bottomAppBarWithCustomArrangement_heightIsFromSpec() {
         rule
             .setMaterialContentForSizeAssertions {
-                BottomAppBar(
-                    horizontalArrangement = BottomAppBarDefaults.HorizontalArrangement,
+                FlexibleBottomAppBar(
+                    horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
                     content = {}
                 )
             }
-            .assertHeightIsEqualTo(64.dp) // TODO tokens
+            .assertHeightIsEqualTo(BottomAppBarDefaults.FlexibleBottomAppBarHeight)
+            .assertWidthIsEqualTo(rule.rootWidth())
+    }
+
+    @Test
+    fun bottomAppBarWithCustomHeight() {
+        val height = 128.dp
+        rule
+            .setMaterialContentForSizeAssertions {
+                FlexibleBottomAppBar(
+                    horizontalArrangement = BottomAppBarDefaults.FlexibleFixedHorizontalArrangement,
+                    expandedHeight = height,
+                    content = {}
+                )
+            }
+            .assertHeightIsEqualTo(height)
             .assertWidthIsEqualTo(rule.rootWidth())
     }
 
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
index 7a2851b..e54b4b2 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxScreenshotTest.kt
@@ -29,8 +29,12 @@
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.input.InputMode
 import androidx.compose.ui.input.InputModeManager
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.state.ToggleableState
@@ -311,6 +315,73 @@
         assertToggeableAgainstGolden("checkBox_${scheme.name}_customCheckboxColorsConstruct")
     }
 
+    @Test
+    fun checkBox_customStroke_checked() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                Checkbox(
+                    modifier = wrap,
+                    checked = true,
+                    onCheckedChange = {},
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_checked")
+    }
+
+    @Test
+    fun checkBox_customStroke_unchecked() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            // Have the stroke thinner so we can verify it's being applied to the rounded box.
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() / 4 },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                Checkbox(
+                    modifier = wrap,
+                    checked = false,
+                    onCheckedChange = {},
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_unchecked")
+    }
+
+    @Test
+    fun checkBox_customStroke_indeterminate() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            val stroke =
+                Stroke(
+                    width = with(LocalDensity.current) { CheckboxDefaults.StrokeWidth.toPx() },
+                    cap = StrokeCap.Round,
+                    join = StrokeJoin.Round
+                )
+            Box(wrap.testTag(wrapperTestTag)) {
+                TriStateCheckbox(
+                    state = ToggleableState.Indeterminate,
+                    checkmarkStroke = stroke,
+                    outlineStroke = stroke,
+                    modifier = wrap,
+                    onClick = {}
+                )
+            }
+        }
+        assertToggeableAgainstGolden("checkBox_${scheme.name}_customStroke_indeterminate")
+    }
+
     @Composable
     private fun Checkboxes(colors: CheckboxColors) {
         TriStateCheckbox(state = ToggleableState.Off, onClick = {}, colors = colors)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
index 3b1550a..b979580 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/CheckboxTest.kt
@@ -27,6 +27,8 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.SemanticsProperties
@@ -54,6 +56,7 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -230,11 +233,72 @@
         )
     }
 
-    @OptIn(ExperimentalMaterial3Api::class)
+    @Test
+    fun checkBoxTest_MaterialSize_WhenChecked_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = On,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenChecked_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = On,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenUnchecked_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Off,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenUnchecked_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Off,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenIndeterminate_withThickStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Indeterminate,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth * 3
+        )
+    }
+
+    @Test
+    fun checkBoxTest_MaterialSize_WhenIndeterminate_withThinStroke_withoutMinimumTouchTarget() {
+        materialSizeTestForValue(
+            checkboxValue = Indeterminate,
+            clickable = false, // Ensure a minimum size with clickable false and no min touch target
+            minimumTouchTarget = false,
+            strokeWidth = CheckboxDefaults.StrokeWidth / 3
+        )
+    }
+
+    @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
     private fun materialSizeTestForValue(
         checkboxValue: ToggleableState,
         clickable: Boolean,
-        minimumTouchTarget: Boolean
+        minimumTouchTarget: Boolean,
+        strokeWidth: Dp? = null,
     ) {
         rule
             .setMaterialContentForSizeAssertions {
@@ -242,14 +306,29 @@
                     LocalMinimumInteractiveComponentSize provides
                         if (minimumTouchTarget) 48.dp else 0.dp
                 ) {
-                    TriStateCheckbox(
-                        state = checkboxValue,
-                        onClick =
-                            if (clickable) {
-                                {}
-                            } else null,
-                        enabled = false
-                    )
+                    if (strokeWidth == null) {
+                        TriStateCheckbox(
+                            state = checkboxValue,
+                            onClick =
+                                if (clickable) {
+                                    {}
+                                } else null,
+                            enabled = false
+                        )
+                    } else {
+                        val strokeWidthPx =
+                            Stroke(width = with(LocalDensity.current) { strokeWidth.toPx() })
+                        TriStateCheckbox(
+                            state = checkboxValue,
+                            onClick =
+                                if (clickable) {
+                                    {}
+                                } else null,
+                            enabled = false,
+                            checkmarkStroke = strokeWidthPx,
+                            outlineStroke = strokeWidthPx
+                        )
+                    }
                 }
             }
             .run {
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.android.kt
index 12c544b..4c9bf48 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.android.kt
@@ -43,14 +43,23 @@
 internal actual fun rememberAccessibilityServiceState(
     listenToTouchExplorationState: Boolean,
     listenToSwitchAccessState: Boolean,
+    listenToVoiceAccessState: Boolean,
 ): State<Boolean> {
     val context = LocalContext.current
     val accessibilityManager =
         context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
 
     val listener =
-        remember(listenToTouchExplorationState, listenToSwitchAccessState) {
-            Listener(listenToTouchExplorationState, listenToSwitchAccessState)
+        remember(
+            listenToTouchExplorationState,
+            listenToSwitchAccessState,
+            listenToVoiceAccessState,
+        ) {
+            Listener(
+                listenToTouchExplorationState = listenToTouchExplorationState,
+                listenToSwitchAccessState = listenToSwitchAccessState,
+                listenToVoiceAccessState = listenToVoiceAccessState,
+            )
         }
 
     ObserveState(
@@ -85,7 +94,8 @@
 @Stable
 private class Listener(
     listenToTouchExplorationState: Boolean,
-    listenToSwitchAccessState: Boolean,
+    val listenToSwitchAccessState: Boolean,
+    val listenToVoiceAccessState: Boolean,
 ) : AccessibilityStateChangeListener, State<Boolean> {
     private var accessibilityEnabled by mutableStateOf(false)
 
@@ -102,13 +112,18 @@
             null
         }
 
-    private val switchAccessListener =
-        if (listenToSwitchAccessState && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+    private val otherA11yServicesListener =
+        if (
+            (listenToSwitchAccessState || listenToVoiceAccessState) &&
+                Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
+        ) {
             object : AccessibilityServicesStateChangeListener {
-                var enabled by mutableStateOf(false)
+                var switchAccessEnabled by mutableStateOf(false)
+                var voiceAccessEnabled by mutableStateOf(false)
 
                 override fun onAccessibilityServicesStateChanged(am: AccessibilityManager) {
-                    enabled = am.switchAccessEnabled
+                    switchAccessEnabled = am.switchAccessEnabled
+                    voiceAccessEnabled = am.voiceAccessEnabled
                 }
             }
         } else {
@@ -118,14 +133,25 @@
     private val AccessibilityManager.switchAccessEnabled
         get() =
             getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC).fastAny {
-                it.settingsActivityName?.contains(SwitchAccessActivityName) == true
+                it.settingsActivityName?.contains(SwitchAccessActivityName, ignoreCase = true) ==
+                    true
+            }
+
+    private val AccessibilityManager.voiceAccessEnabled
+        get() =
+            getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC).fastAny {
+                it.settingsActivityName?.contains(VoiceAccessActivityName, ignoreCase = true) ==
+                    true
             }
 
     override val value: Boolean
         get() =
             accessibilityEnabled &&
-                ((touchExplorationListener?.enabled ?: false) ||
-                    (switchAccessListener?.enabled ?: false))
+                ((touchExplorationListener?.enabled == true) ||
+                    (listenToSwitchAccessState &&
+                        otherA11yServicesListener?.switchAccessEnabled == true) ||
+                    (listenToVoiceAccessState &&
+                        otherA11yServicesListener?.voiceAccessEnabled == true))
 
     override fun onAccessibilityStateChanged(enabled: Boolean) {
         accessibilityEnabled = enabled
@@ -139,8 +165,9 @@
             am.addTouchExplorationStateChangeListener(it)
         }
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            switchAccessListener?.let {
-                it.enabled = am.switchAccessEnabled
+            otherA11yServicesListener?.let {
+                it.switchAccessEnabled = am.switchAccessEnabled
+                it.voiceAccessEnabled = am.voiceAccessEnabled
                 Api33Impl.addAccessibilityServicesStateChangeListener(am, it)
             }
         }
@@ -150,7 +177,7 @@
         am.removeAccessibilityStateChangeListener(this)
         touchExplorationListener?.let { am.removeTouchExplorationStateChangeListener(it) }
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-            switchAccessListener?.let {
+            otherA11yServicesListener?.let {
                 Api33Impl.removeAccessibilityServicesStateChangeListener(am, it)
             }
         }
@@ -177,3 +204,4 @@
 }
 
 private const val SwitchAccessActivityName = "SwitchAccess"
+private const val VoiceAccessActivityName = "VoiceAccess"
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
index 610a237..04de614 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
@@ -1050,7 +1050,7 @@
  * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external"
  * target="_blank">Material Design bottom app bar</a>.
  *
- * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ * A bottom app bar displays navigation and key actions at the bottom of small screens.
  *
  * ![Bottom app bar
  * image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
@@ -1106,7 +1106,7 @@
  * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external"
  * target="_blank">Material Design bottom app bar</a>.
  *
- * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ * A bottom app bar displays navigation and key actions at the bottom of small screens.
  *
  * ![Bottom app bar
  * image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
@@ -1186,7 +1186,7 @@
  * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external"
  * target="_blank">Material Design bottom app bar</a>.
  *
- * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ * A bottom app bar displays navigation and key actions at the bottom of small screens.
  *
  * ![Bottom app bar
  * image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
@@ -1235,7 +1235,7 @@
  * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external"
  * target="_blank">Material Design bottom app bar</a>.
  *
- * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ * A bottom app bar displays navigation and key actions at the bottom of small screens.
  *
  * ![Bottom app bar
  * image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
@@ -1288,14 +1288,16 @@
     )
 }
 
+// TODO missing image of the flexible bottom app bar.
 /**
  * <a href="https://m3.material.io/components/bottom-app-bar/overview" class="external"
- * target="_blank">Material Design bottom app bar</a>.
+ * target="_blank">Material Design flexible bottom app bar</a>.
  *
- * A bottom app bar displays navigation and key actions at the bottom of mobile screens.
+ * A flexible bottom app bar displays navigation and key actions at the bottom of small screens.
  *
- * ![Bottom app bar
- * image](https://developer.android.com/images/reference/androidx/compose/material3/bottom-app-bar.png)
+ * This variation of the Bottom app bar has a [horizontalArrangement] parameter for controlling the
+ * way the content is arranged. Also, it allows more flexibility in controlling the bar's expanded
+ * height with an [expandedHeight] value.
  *
  * If you are interested in displaying a [FloatingActionButton], consider using another overload
  * that takes a [FloatingActionButton] parameter.
@@ -1311,7 +1313,6 @@
  * @sample androidx.compose.material3.samples.ExitAlwaysBottomAppBarSpacedEvenly
  * @sample androidx.compose.material3.samples.ExitAlwaysBottomAppBarFixed
  * @sample androidx.compose.material3.samples.ExitAlwaysBottomAppBarFixedVibrant
- * @param horizontalArrangement the horizontal arrangement of the content.
  * @param modifier the [Modifier] to be applied to this BottomAppBar
  * @param containerColor the color used for the background of this BottomAppBar. Use
  *   [Color.Transparent] to have no color.
@@ -1319,6 +1320,13 @@
  *   the matching content color for [containerColor], or to the current [LocalContentColor] if
  *   [containerColor] is not a color from the theme.
  * @param contentPadding the padding applied to the content of this BottomAppBar
+ * @param horizontalArrangement the horizontal arrangement of the content inside this BottomAppBar
+ * @param expandedHeight the maximum height this bottom bar can reach when fully expanded. If a
+ *   [scrollBehavior] is provided, the bar might collapse or expand based on scrolling. In that
+ *   case, this value sets the upper limit for the bar's height during expansion. This [Dp] value
+ *   must be specified, finite, and greater than zero; otherwise,
+ *   [BottomAppBarDefaults.FlexibleBottomAppBarHeight] will be used as a default. In case the
+ *   [scrollBehavior] is `null`, this value will simply be the fixed height of the bottom bar.
  * @param windowInsets a window insets that app bar will respect.
  * @param scrollBehavior a [BottomAppBarScrollBehavior] which holds various offset values that will
  *   be applied by this bottom app bar to set up its height. A scroll behavior is designed to work
@@ -1330,23 +1338,30 @@
 @OptIn(ExperimentalMaterial3Api::class)
 @ExperimentalMaterial3ExpressiveApi
 @Composable
-fun BottomAppBar(
-    horizontalArrangement: Arrangement.Horizontal,
+fun FlexibleBottomAppBar(
     modifier: Modifier = Modifier,
     containerColor: Color = BottomAppBarDefaults.containerColor,
     contentColor: Color = contentColorFor(containerColor),
-    contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp), // TODO tokens
+    contentPadding: PaddingValues = BottomAppBarDefaults.FlexibleContentPadding,
+    horizontalArrangement: Arrangement.Horizontal =
+        BottomAppBarDefaults.FlexibleHorizontalArrangement,
+    expandedHeight: Dp = BottomAppBarDefaults.FlexibleBottomAppBarHeight,
     windowInsets: WindowInsets = BottomAppBarDefaults.windowInsets,
     scrollBehavior: BottomAppBarScrollBehavior? = null,
     content: @Composable RowScope.() -> Unit
 ) {
     BottomAppBarLayout(
-        containerHeight = 64.dp, // TODO tokens
+        containerHeight =
+            if (expandedHeight.isFinite && expandedHeight.isSpecified && expandedHeight > 0.dp) {
+                expandedHeight
+            } else {
+                BottomAppBarDefaults.FlexibleBottomAppBarHeight
+            },
         horizontalArrangement = horizontalArrangement,
         modifier = modifier,
         containerColor = containerColor,
         contentColor = contentColor,
-        tonalElevation = BottomAppBarDefaults.ContainerElevation,
+        tonalElevation = AppBarTokens.ContainerElevation,
         contentPadding = contentPadding,
         windowInsets = windowInsets,
         scrollBehavior = scrollBehavior,
@@ -2192,7 +2207,34 @@
     val bottomAppBarFabColor: Color
         @Composable get() = FabSecondaryContainerTokens.ContainerColor.value
 
-    val HorizontalArrangement =
+    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+    @get:ExperimentalMaterial3ExpressiveApi
+    @ExperimentalMaterial3ExpressiveApi
+    /** Default padding used for [FlexibleBottomAppBar]. */
+    val FlexibleContentPadding = PaddingValues(horizontal = 16.dp) // TODO tokens
+
+    /**
+     * Default height of a flexible [FlexibleBottomAppBar]. The height here represents the height of
+     * the bottom app bar in its expanded state.
+     */
+    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+    @get:ExperimentalMaterial3ExpressiveApi
+    @ExperimentalMaterial3ExpressiveApi
+    val FlexibleBottomAppBarHeight = AppBarSmallTokens.ContainerHeight
+
+    /** A default [Arrangement] that will be used to space a [FlexibleBottomAppBar]'s content. */
+    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+    @get:ExperimentalMaterial3ExpressiveApi
+    @ExperimentalMaterial3ExpressiveApi
+    val FlexibleHorizontalArrangement: Arrangement.Horizontal = Arrangement.SpaceBetween
+
+    /**
+     * An [Arrangement] that will be used to space [FlexibleBottomAppBar]'s with a fixed spacing.
+     */
+    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+    @get:ExperimentalMaterial3ExpressiveApi
+    @ExperimentalMaterial3ExpressiveApi
+    val FlexibleFixedHorizontalArrangement: Arrangement.Horizontal =
         Arrangement.spacedBy(32.dp, Alignment.CenterHorizontally) // TODO tokens
 
     // TODO: note that this scroll behavior may impact assistive technologies making the component
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
index 0fd3f81..1888a07 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Checkbox.kt
@@ -48,6 +48,7 @@
 import androidx.compose.ui.graphics.drawscope.Fill
 import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.unit.dp
@@ -96,6 +97,7 @@
     colors: CheckboxColors = CheckboxDefaults.colors(),
     interactionSource: MutableInteractionSource? = null
 ) {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
     TriStateCheckbox(
         state = ToggleableState(checked),
         onClick =
@@ -104,6 +106,72 @@
             } else {
                 null
             },
+        checkmarkStroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square),
+        outlineStroke = Stroke(width = strokeWidthPx),
+        modifier = modifier,
+        enabled = enabled,
+        colors = colors,
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * <a href="https://m3.material.io/components/checkbox/overview" class="external"
+ * target="_blank">Material Design checkbox</a>.
+ *
+ * Checkboxes allow users to select one or more items from a set. Checkboxes can turn an option on
+ * or off.
+ *
+ * ![Checkbox
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/checkbox.png)
+ *
+ * This Checkbox function offers greater flexibility in visual customization. Using the [Stroke]
+ * parameters, you can control the appearance of both the checkmark and the box that surrounds it.
+ *
+ * A sample of a `Checkbox` that uses a [Stroke] with rounded [StrokeCap] and
+ * [androidx.compose.ui.graphics.StrokeJoin]:
+ *
+ * @sample androidx.compose.material3.samples.CheckboxRoundedStrokesSample
+ * @param checked whether this checkbox is checked or unchecked
+ * @param onCheckedChange called when this checkbox is clicked. If `null`, then this checkbox will
+ *   not be interactable, unless something else handles its input events and updates its state.
+ * @param checkmarkStroke stroke for the checkmark.
+ * @param outlineStroke stroke for the checkmark's box outline. Note that this stroke is applied
+ *   when drawing the outline's rounded rectangle, so attributions such as
+ *   [androidx.compose.ui.graphics.StrokeJoin] will be ignored.
+ * @param modifier the [Modifier] to be applied to this checkbox
+ * @param enabled controls the enabled state of this checkbox. When `false`, this component will not
+ *   respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param colors [CheckboxColors] that will be used to resolve the colors used for this checkbox in
+ *   different states. See [CheckboxDefaults.colors].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this checkbox. You can use this to change the checkbox's appearance
+ *   or preview the checkbox in different states. Note that if `null` is provided, interactions will
+ *   still happen internally.
+ * @see [TriStateCheckbox] if you require support for an indeterminate state.
+ */
+@Composable
+fun Checkbox(
+    checked: Boolean,
+    onCheckedChange: ((Boolean) -> Unit)?,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: CheckboxColors = CheckboxDefaults.colors(),
+    interactionSource: MutableInteractionSource? = null
+) {
+    TriStateCheckbox(
+        state = ToggleableState(checked),
+        onClick =
+            if (onCheckedChange != null) {
+                { onCheckedChange(!checked) }
+            } else {
+                null
+            },
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke,
         modifier = modifier,
         enabled = enabled,
         colors = colors,
@@ -148,6 +216,68 @@
     colors: CheckboxColors = CheckboxDefaults.colors(),
     interactionSource: MutableInteractionSource? = null
 ) {
+    val strokeWidthPx = with(LocalDensity.current) { floor(CheckboxDefaults.StrokeWidth.toPx()) }
+    TriStateCheckbox(
+        state = state,
+        onClick = onClick,
+        checkmarkStroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square),
+        outlineStroke = Stroke(width = strokeWidthPx),
+        modifier = modifier,
+        enabled = enabled,
+        colors = colors,
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * <a href="https://m3.material.io/components/checkbox/guidelines" class="external"
+ * target="_blank">Material Design checkbox</a> parent.
+ *
+ * Checkboxes can have a parent-child relationship with other checkboxes. When the parent checkbox
+ * is checked, all child checkboxes are checked. If a parent checkbox is unchecked, all child
+ * checkboxes are unchecked. If some, but not all, child checkboxes are checked, the parent checkbox
+ * becomes an indeterminate checkbox.
+ *
+ * ![Checkbox
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/indeterminate-checkbox.png)
+ *
+ * This Checkbox function offers greater flexibility in visual customization. Using the [Stroke]
+ * parameters, you can control the appearance of both the checkmark and the box that surrounds it.
+ *
+ * A sample of a `TriStateCheckbox` that uses a [Stroke] with rounded [StrokeCap] and
+ * [androidx.compose.ui.graphics.StrokeJoin]:
+ *
+ * @sample androidx.compose.material3.samples.TriStateCheckboxRoundedStrokesSample
+ * @param state whether this checkbox is checked, unchecked, or in an indeterminate state
+ * @param onClick called when this checkbox is clicked. If `null`, then this checkbox will not be
+ *   interactable, unless something else handles its input events and updates its [state].
+ * @param checkmarkStroke stroke for the checkmark.
+ * @param outlineStroke stroke for the checkmark's box outline. Note that this stroke is applied
+ *   when drawing the outline's rounded rectangle, so attributions such as
+ *   [androidx.compose.ui.graphics.StrokeJoin] will be ignored.
+ * @param modifier the [Modifier] to be applied to this checkbox
+ * @param enabled controls the enabled state of this checkbox. When `false`, this component will not
+ *   respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param colors [CheckboxColors] that will be used to resolve the colors used for this checkbox in
+ *   different states. See [CheckboxDefaults.colors].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this checkbox. You can use this to change the checkbox's appearance
+ *   or preview the checkbox in different states. Note that if `null` is provided, interactions will
+ *   still happen internally.
+ * @see [Checkbox] if you want a simple component that represents Boolean state
+ */
+@Composable
+fun TriStateCheckbox(
+    state: ToggleableState,
+    onClick: (() -> Unit)?,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: CheckboxColors = CheckboxDefaults.colors(),
+    interactionSource: MutableInteractionSource? = null
+) {
     val toggleableModifier =
         if (onClick != null) {
             Modifier.triStateToggleable(
@@ -175,7 +305,9 @@
                 )
                 .then(toggleableModifier)
                 .padding(CheckboxDefaultPadding),
-        colors = colors
+        colors = colors,
+        checkmarkStroke = checkmarkStroke,
+        outlineStroke = outlineStroke
     )
 }
 
@@ -255,6 +387,12 @@
                     )
                     .also { defaultCheckboxColorsCached = it }
         }
+
+    /**
+     * The default stroke width for a [Checkbox]. This width will be used for the checkmark when the
+     * `Checkbox` is in a checked or indeterminate states, or for the outline when it's unchecked.
+     */
+    val StrokeWidth = 2.dp
 }
 
 @Composable
@@ -262,7 +400,9 @@
     enabled: Boolean,
     value: ToggleableState,
     modifier: Modifier,
-    colors: CheckboxColors
+    colors: CheckboxColors,
+    checkmarkStroke: Stroke,
+    outlineStroke: Stroke,
 ) {
     val transition = updateTransition(value)
     val defaultAnimationSpec = MotionSchemeKeyTokens.DefaultSpatial.value<Float>()
@@ -306,31 +446,24 @@
     val boxColor = colors.boxColor(enabled, value)
     val borderColor = colors.borderColor(enabled, value)
     Canvas(modifier.wrapContentSize(Alignment.Center).requiredSize(CheckboxSize)) {
-        val strokeWidthPx = floor(StrokeWidth.toPx())
         drawBox(
             boxColor = boxColor.value,
             borderColor = borderColor.value,
             radius = RadiusSize.toPx(),
-            strokeWidth = strokeWidthPx
+            stroke = outlineStroke
         )
         drawCheck(
             checkColor = checkColor.value,
             checkFraction = checkDrawFraction.value,
             crossCenterGravitation = checkCenterGravitationShiftFraction.value,
-            strokeWidthPx = strokeWidthPx,
+            stroke = checkmarkStroke,
             drawingCache = checkCache
         )
     }
 }
 
-private fun DrawScope.drawBox(
-    boxColor: Color,
-    borderColor: Color,
-    radius: Float,
-    strokeWidth: Float
-) {
-    val halfStrokeWidth = strokeWidth / 2.0f
-    val stroke = Stroke(strokeWidth)
+private fun DrawScope.drawBox(boxColor: Color, borderColor: Color, radius: Float, stroke: Stroke) {
+    val halfStrokeWidth = stroke.width / 2.0f
     val checkboxSize = size.width
     if (boxColor == borderColor) {
         drawRoundRect(
@@ -342,15 +475,15 @@
     } else {
         drawRoundRect(
             boxColor,
-            topLeft = Offset(strokeWidth, strokeWidth),
-            size = Size(checkboxSize - strokeWidth * 2, checkboxSize - strokeWidth * 2),
-            cornerRadius = CornerRadius(max(0f, radius - strokeWidth)),
+            topLeft = Offset(stroke.width, stroke.width),
+            size = Size(checkboxSize - stroke.width * 2, checkboxSize - stroke.width * 2),
+            cornerRadius = CornerRadius(max(0f, radius - stroke.width)),
             style = Fill
         )
         drawRoundRect(
             borderColor,
             topLeft = Offset(halfStrokeWidth, halfStrokeWidth),
-            size = Size(checkboxSize - strokeWidth, checkboxSize - strokeWidth),
+            size = Size(checkboxSize - stroke.width, checkboxSize - stroke.width),
             cornerRadius = CornerRadius(radius - halfStrokeWidth),
             style = stroke
         )
@@ -361,10 +494,9 @@
     checkColor: Color,
     checkFraction: Float,
     crossCenterGravitation: Float,
-    strokeWidthPx: Float,
+    stroke: Stroke,
     drawingCache: CheckDrawingCache
 ) {
-    val stroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Square)
     val width = size.width
     val checkCrossX = 0.4f
     val checkCrossY = 0.7f
@@ -380,13 +512,13 @@
     val gravitatedRightY = lerp(rightY, 0.5f, crossCenterGravitation)
 
     with(drawingCache) {
-        checkPath.reset()
+        checkPath.rewind()
         checkPath.moveTo(width * leftX, width * gravitatedLeftY)
         checkPath.lineTo(width * gravitatedCrossX, width * gravitatedCrossY)
         checkPath.lineTo(width * rightX, width * gravitatedRightY)
         // TODO: replace with proper declarative non-android alternative when ready (b/158188351)
         pathMeasure.setPath(checkPath, false)
-        pathToDraw.reset()
+        pathToDraw.rewind()
         pathMeasure.getSegment(0f, pathMeasure.length * checkFraction, pathToDraw, true)
     }
     drawPath(drawingCache.pathToDraw, checkColor, style = stroke)
@@ -607,5 +739,4 @@
 // TODO(b/188529841): Update the padding and size when the Checkbox spec is finalized.
 private val CheckboxDefaultPadding = 2.dp
 private val CheckboxSize = 20.dp
-private val StrokeWidth = 2.dp
 private val RadiusSize = 2.dp
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.kt
index e03821f..9986bf1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.kt
@@ -25,9 +25,11 @@
  * @param listenToTouchExplorationState whether to track the enabled/disabled state of touch
  *   exploration (i.e. TalkBack)
  * @param listenToSwitchAccessState whether to track the enabled/disabled state of Switch Access
+ * @param listenToVoiceAccessState whether to track the enabled/disabled state of Voice Access
  */
 @Composable
 internal expect fun rememberAccessibilityServiceState(
     listenToTouchExplorationState: Boolean = true,
     listenToSwitchAccessState: Boolean = true,
+    listenToVoiceAccessState: Boolean = true,
 ): State<Boolean>
diff --git a/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt
index e68e24c..6654fd6 100644
--- a/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt
@@ -24,4 +24,5 @@
 internal actual fun rememberAccessibilityServiceState(
     listenToTouchExplorationState: Boolean,
     listenToSwitchAccessState: Boolean,
+    listenToVoiceAccessState: Boolean,
 ): State<Boolean> = implementedInJetBrainsFork()
diff --git a/compose/runtime/runtime/proguard-rules.pro b/compose/runtime/runtime/proguard-rules.pro
index 6e78193..e69e0a1 100644
--- a/compose/runtime/runtime/proguard-rules.pro
+++ b/compose/runtime/runtime/proguard-rules.pro
@@ -17,7 +17,7 @@
 # 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.runtime.** {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.runtime.** {
     # java.lang.Void == methods that return Nothing
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
@@ -31,3 +31,4 @@
     static void compose*RuntimeError(...);
     static java.lang.Void compose*RuntimeError(...);
 }
+
diff --git a/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.android.kt b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.android.kt
new file mode 100644
index 0000000..c487bdc
--- /dev/null
+++ b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.android.kt
@@ -0,0 +1,29 @@
+/*
+ * 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("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
+
+package androidx.compose.runtime.collection
+
+internal actual inline fun <T> Array<out T>.fastCopyInto(
+    destination: Array<T>,
+    destinationOffset: Int,
+    startIndex: Int,
+    endIndex: Int
+): Array<T> {
+    System.arraycopy(this, startIndex, destination, destinationOffset, endIndex - startIndex)
+    return destination
+}
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
index a295937..afd4db85 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
@@ -23,6 +23,7 @@
 import androidx.collection.MutableIntSet
 import androidx.collection.MutableObjectList
 import androidx.collection.mutableIntListOf
+import androidx.compose.runtime.collection.fastCopyInto
 import androidx.compose.runtime.platform.makeSynchronizedObject
 import androidx.compose.runtime.platform.synchronized
 import androidx.compose.runtime.snapshots.fastAny
@@ -2122,7 +2123,7 @@
         //  4) copy the slots to their new location
         if (moveDataLen > 0) {
             val slots = slots
-            slots.copyInto(
+            slots.fastCopyInto(
                 destination = slots,
                 destinationOffset = destinationSlot,
                 startIndex = dataIndexToDataAddress(dataStart + moveDataLen),
@@ -2206,7 +2207,7 @@
             )
             val slots = toWriter.slots
             val currentSlot = toWriter.currentSlot
-            fromWriter.slots.copyInto(
+            fromWriter.slots.fastCopyInto(
                 destination = slots,
                 destinationOffset = currentSlot,
                 startIndex = sourceSlotsStart,
@@ -2676,7 +2677,7 @@
             val slots = slots
             if (index < gapStart) {
                 // move the gap down to index by shifting the data up.
-                slots.copyInto(
+                slots.fastCopyInto(
                     destination = slots,
                     destinationOffset = index + gapLen,
                     startIndex = index,
@@ -2684,7 +2685,7 @@
                 )
             } else {
                 // Shift the data down, leaving the gap at index
-                slots.copyInto(
+                slots.fastCopyInto(
                     destination = slots,
                     destinationOffset = gapStart,
                     startIndex = gapStart + gapLen,
@@ -2830,13 +2831,13 @@
                 val newGapEndAddress = gapStart + newGapLen
 
                 // Copy the old arrays into the new arrays
-                slots.copyInto(
+                slots.fastCopyInto(
                     destination = newData,
                     destinationOffset = 0,
                     startIndex = 0,
                     endIndex = gapStart
                 )
-                slots.copyInto(
+                slots.fastCopyInto(
                     destination = newData,
                     destinationOffset = newGapEndAddress,
                     startIndex = oldGapEndAddress,
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
index 03989dd..d11eacb 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
+@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
+
 package androidx.compose.runtime
 
+import kotlin.jvm.JvmField
 import kotlin.jvm.JvmInline
+import kotlin.math.min
 
 @JvmInline
 internal value class Stack<T>(private val backing: ArrayList<T> = ArrayList()) {
@@ -42,22 +46,32 @@
 }
 
 internal class IntStack {
-    private var slots = IntArray(10)
-    private var tos = 0
+    @JvmField internal var slots = IntArray(10)
+    @JvmField internal var tos = 0
 
-    val size: Int
+    inline val size: Int
         get() = tos
 
+    private fun resize(): IntArray {
+        val copy = slots.copyOf(slots.size * 2)
+        slots = copy
+        return copy
+    }
+
     fun push(value: Int) {
+        var slots = slots
         if (tos >= slots.size) {
-            slots = slots.copyOf(slots.size * 2)
+            slots = resize()
         }
         slots[tos++] = value
     }
 
     fun pop(): Int = slots[--tos]
 
-    fun peekOr(default: Int): Int = if (tos > 0) peek() else default
+    fun peekOr(default: Int): Int {
+        val index = tos - 1
+        return if (index >= 0) slots[index] else default
+    }
 
     fun peek() = slots[tos - 1]
 
@@ -65,16 +79,20 @@
 
     fun peek(index: Int) = slots[index]
 
-    fun isEmpty() = tos == 0
+    inline fun isEmpty() = tos == 0
 
-    fun isNotEmpty() = tos != 0
+    inline fun isNotEmpty() = tos != 0
 
     fun clear() {
         tos = 0
     }
 
     fun indexOf(value: Int): Int {
-        for (i in 0 until tos) if (slots[i] == value) return i
+        val slots = slots
+        val end = min(slots.size, tos)
+        for (i in 0 until end) {
+            if (slots[i] == value) return i
+        }
         return -1
     }
 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/changelist/Operations.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/changelist/Operations.kt
index f250bc8..efa946a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/changelist/Operations.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/changelist/Operations.kt
@@ -24,6 +24,7 @@
 import androidx.compose.runtime.RememberManager
 import androidx.compose.runtime.SlotWriter
 import androidx.compose.runtime.changelist.Operation.ObjectParameter
+import androidx.compose.runtime.collection.fastCopyInto
 import androidx.compose.runtime.debugRuntimeCheck
 import androidx.compose.runtime.requirePrecondition
 import kotlin.contracts.ExperimentalContracts
@@ -137,7 +138,7 @@
         val resizeAmount = opCodesSize.coerceAtMost(OperationsMaxResizeAmount)
         @Suppress("UNCHECKED_CAST")
         val newOpCodes = arrayOfNulls<Operation>(opCodesSize + resizeAmount) as Array<Operation>
-        opCodes = opCodes.copyInto(newOpCodes, 0, 0, opCodesSize)
+        opCodes = opCodes.fastCopyInto(newOpCodes, 0, 0, opCodesSize)
     }
 
     private inline fun ensureIntArgsSizeAtLeast(requiredSize: Int) {
@@ -162,7 +163,7 @@
 
     private fun resizeObjectArgs(currentSize: Int, requiredSize: Int) {
         val newObjectArgs = arrayOfNulls<Any>(determineNewSize(currentSize, requiredSize))
-        objectArgs.copyInto(newObjectArgs, 0, 0, currentSize)
+        objectArgs.fastCopyInto(newObjectArgs, 0, 0, currentSize)
         objectArgs = newObjectArgs
     }
 
@@ -291,7 +292,7 @@
         other.pushOp(op)
 
         // Move the objects then null out our contents
-        objectArgs.copyInto(
+        objectArgs.fastCopyInto(
             destination = other.objectArgs,
             destinationOffset = other.objectArgsSize - op.objects,
             startIndex = objectArgsSize - op.objects,
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.kt
new file mode 100644
index 0000000..03c2546
--- /dev/null
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.runtime.collection
+
+/**
+ * Equivalent of Array.copyInto() with an implementation designed to avoid unnecessary null checks
+ * and exception throws on Android after inlining.
+ */
+internal expect fun <T> Array<out T>.fastCopyInto(
+    destination: Array<T>,
+    destinationOffset: Int,
+    startIndex: Int,
+    endIndex: Int
+): Array<T>
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
index 1315b32..c16d977 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
@@ -66,7 +66,7 @@
         ensureCapacity(size + 1)
         val content = content
         if (index != size) {
-            content.copyInto(
+            content.fastCopyInto(
                 destination = content,
                 destinationOffset = index + 1,
                 startIndex = index,
@@ -83,12 +83,13 @@
      */
     fun addAll(index: Int, elements: List<T>): Boolean {
         if (elements.isEmpty()) return false
-        ensureCapacity(size + elements.size)
+        val elementsSize = elements.size
+        ensureCapacity(size + elementsSize)
         val content = content
         if (index != size) {
-            content.copyInto(
+            content.fastCopyInto(
                 destination = content,
-                destinationOffset = index + elements.size,
+                destinationOffset = index + elementsSize,
                 startIndex = index,
                 endIndex = size
             )
@@ -96,7 +97,7 @@
         for (i in elements.indices) {
             content[index + i] = elements[i]
         }
-        size += elements.size
+        size += elementsSize
         return true
     }
 
@@ -105,24 +106,25 @@
      * that are in the way.
      */
     fun addAll(index: Int, elements: MutableVector<T>): Boolean {
-        if (elements.isEmpty()) return false
-        ensureCapacity(size + elements.size)
+        val elementsSize = elements.size
+        if (elementsSize == 0) return false
+        ensureCapacity(size + elementsSize)
         val content = content
         if (index != size) {
-            content.copyInto(
+            content.fastCopyInto(
                 destination = content,
-                destinationOffset = index + elements.size,
+                destinationOffset = index + elementsSize,
                 startIndex = index,
                 endIndex = size
             )
         }
-        elements.content.copyInto(
+        elements.content.fastCopyInto(
             destination = content,
             destinationOffset = index,
             startIndex = 0,
-            endIndex = elements.size
+            endIndex = elementsSize
         )
-        size += elements.size
+        size += elementsSize
         return true
     }
 
@@ -147,12 +149,13 @@
      * [MutableVector] was changed.
      */
     fun addAll(@Suppress("ArrayReturn") elements: Array<T>): Boolean {
-        if (elements.isEmpty()) {
+        val elementsSize = elements.size
+        if (elementsSize == 0) {
             return false
         }
-        ensureCapacity(size + elements.size)
-        elements.copyInto(destination = content, destinationOffset = size)
-        size += elements.size
+        ensureCapacity(size + elementsSize)
+        elements.fastCopyInto(destination = content, destinationOffset = size, 0, elementsSize)
+        size += elementsSize
         return true
     }
 
@@ -162,18 +165,19 @@
      */
     fun addAll(index: Int, elements: Collection<T>): Boolean {
         if (elements.isEmpty()) return false
-        ensureCapacity(size + elements.size)
+        val elementsSize = elements.size
+        ensureCapacity(size + elementsSize)
         val content = content
         if (index != size) {
-            content.copyInto(
+            content.fastCopyInto(
                 destination = content,
-                destinationOffset = index + elements.size,
+                destinationOffset = index + elementsSize,
                 startIndex = index,
                 endIndex = size
             )
         }
         elements.forEachIndexed { i, item -> content[index + i] = item }
-        size += elements.size
+        size += elementsSize
         return true
     }
 
@@ -293,7 +297,7 @@
         val oldSize = oldContent.size
         val newSize = max(capacity, oldSize * 2)
         val newContent = arrayOfNulls<Any?>(newSize) as Array<T?>
-        oldContent.copyInto(newContent, 0, 0, oldSize)
+        oldContent.fastCopyInto(newContent, 0, 0, oldSize)
         content = newContent
     }
 
@@ -694,7 +698,7 @@
         val content = content
         val item = content[index] as T
         if (index != lastIndex) {
-            content.copyInto(
+            content.fastCopyInto(
                 destination = content,
                 destinationOffset = index,
                 startIndex = index + 1,
@@ -710,7 +714,7 @@
     fun removeRange(start: Int, end: Int) {
         if (end > start) {
             if (end < size) {
-                content.copyInto(
+                content.fastCopyInto(
                     destination = content,
                     destinationOffset = start,
                     startIndex = end,
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotWeakSet.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotWeakSet.kt
index 66075f0a..e70d6fd 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotWeakSet.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotWeakSet.kt
@@ -17,6 +17,7 @@
 package androidx.compose.runtime.snapshots
 
 import androidx.compose.runtime.TestOnly
+import androidx.compose.runtime.collection.fastCopyInto
 import androidx.compose.runtime.internal.WeakReference
 import androidx.compose.runtime.internal.identityHashCode
 
@@ -70,13 +71,18 @@
             val newCapacity = capacity * 2
             val newValues = arrayOfNulls<WeakReference<T>?>(newCapacity)
             val newHashes = IntArray(newCapacity)
-            values.copyInto(
+            values.fastCopyInto(
                 destination = newValues,
                 destinationOffset = insertIndex + 1,
                 startIndex = insertIndex,
                 endIndex = size
             )
-            values.copyInto(destination = newValues, endIndex = insertIndex)
+            values.fastCopyInto(
+                destination = newValues,
+                destinationOffset = 0,
+                startIndex = 0,
+                endIndex = insertIndex
+            )
             hashes.copyInto(
                 destination = newHashes,
                 destinationOffset = insertIndex + 1,
@@ -87,7 +93,7 @@
             values = newValues
             hashes = newHashes
         } else {
-            values.copyInto(
+            values.fastCopyInto(
                 destination = values,
                 destinationOffset = insertIndex + 1,
                 startIndex = insertIndex,
diff --git a/compose/runtime/runtime/src/nonAndroidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.nonAndroid.kt b/compose/runtime/runtime/src/nonAndroidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.nonAndroid.kt
new file mode 100644
index 0000000..2e2c834
--- /dev/null
+++ b/compose/runtime/runtime/src/nonAndroidMain/kotlin/androidx/compose/runtime/collection/ArrayUtils.nonAndroid.kt
@@ -0,0 +1,26 @@
+/*
+ * 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("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
+
+package androidx.compose.runtime.collection
+
+internal actual inline fun <T> Array<out T>.fastCopyInto(
+    destination: Array<T>,
+    destinationOffset: Int,
+    startIndex: Int,
+    endIndex: Int
+): Array<T> = this.copyInto(destination, destinationOffset, startIndex, endIndex)
diff --git a/compose/ui/ui-graphics/proguard-rules.pro b/compose/ui/ui-graphics/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/ui/ui-graphics/proguard-rules.pro
+++ b/compose/ui/ui-graphics/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/IntervalTree.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/IntervalTree.kt
index 1d3b503..8a2ff33 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/IntervalTree.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/IntervalTree.kt
@@ -82,8 +82,7 @@
     // structure beyond what can be found in various descriptions of binary search
     // trees and red/black trees
 
-    @JvmField
-    internal val terminator = Node(Float.MAX_VALUE, Float.MIN_VALUE, null, TreeColor.Black)
+    @JvmField internal val terminator = Node(Float.MAX_VALUE, Float.MIN_VALUE, null, TreeColorBlack)
     @JvmField internal var root = terminator
     @JvmField internal val stack = ArrayList<Node>()
 
@@ -203,7 +202,7 @@
      * @param data Data to associate with the interval
      */
     fun addInterval(start: Float, end: Float, data: T?) {
-        val node = Node(start, end, data, TreeColor.Red)
+        val node = Node(start, end, data, TreeColorRed)
 
         // Update the tree without doing any balancing
         var current = root
@@ -239,44 +238,44 @@
     private fun rebalance(target: Node) {
         var node = target
 
-        while (node !== root && node.parent.color == TreeColor.Red) {
+        while (node !== root && node.parent.color == TreeColorRed) {
             val ancestor = node.parent.parent
             if (node.parent === ancestor.left) {
                 val right = ancestor.right
-                if (right.color == TreeColor.Red) {
-                    right.color = TreeColor.Black
-                    node.parent.color = TreeColor.Black
-                    ancestor.color = TreeColor.Red
+                if (right.color == TreeColorRed) {
+                    right.color = TreeColorBlack
+                    node.parent.color = TreeColorBlack
+                    ancestor.color = TreeColorRed
                     node = ancestor
                 } else {
                     if (node === node.parent.right) {
                         node = node.parent
                         rotateLeft(node)
                     }
-                    node.parent.color = TreeColor.Black
-                    ancestor.color = TreeColor.Red
+                    node.parent.color = TreeColorBlack
+                    ancestor.color = TreeColorRed
                     rotateRight(ancestor)
                 }
             } else {
                 val left = ancestor.left
-                if (left.color == TreeColor.Red) {
-                    left.color = TreeColor.Black
-                    node.parent.color = TreeColor.Black
-                    ancestor.color = TreeColor.Red
+                if (left.color == TreeColorRed) {
+                    left.color = TreeColorBlack
+                    node.parent.color = TreeColorBlack
+                    ancestor.color = TreeColorRed
                     node = ancestor
                 } else {
                     if (node === node.parent.left) {
                         node = node.parent
                         rotateRight(node)
                     }
-                    node.parent.color = TreeColor.Black
-                    ancestor.color = TreeColor.Red
+                    node.parent.color = TreeColorBlack
+                    ancestor.color = TreeColorRed
                     rotateLeft(ancestor)
                 }
             }
         }
 
-        root.color = TreeColor.Black
+        root.color = TreeColorBlack
     }
 
     private fun rotateLeft(node: Node) {
@@ -340,11 +339,6 @@
         }
     }
 
-    internal enum class TreeColor {
-        Red,
-        Black
-    }
-
     internal inner class Node(start: Float, end: Float, data: T?, var color: TreeColor) :
         Interval<T>(start, end, data) {
         var min: Float = start
@@ -378,3 +372,8 @@
         }
     }
 }
+
+private typealias TreeColor = Int
+
+private const val TreeColorRed = 0
+private const val TreeColorBlack = 1
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/PathGeometry.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/PathGeometry.kt
index 53b0d54..4c96e1e 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/PathGeometry.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/PathGeometry.kt
@@ -58,7 +58,7 @@
     // segments.
     var type = iterator.next(points)
     while (type != PathSegment.Type.Done) {
-        @Suppress("KotlinConstantConditions")
+        @Suppress("KotlinConstantConditions", "RedundantSuppression")
         when (type) {
             PathSegment.Type.Move -> {
                 if (!first) {
@@ -175,7 +175,7 @@
 
     var type = iterator.next(points)
     while (type != PathSegment.Type.Done) {
-        @Suppress("KotlinConstantConditions")
+        @Suppress("KotlinConstantConditions", "RedundantSuppression")
         when (type) {
             PathSegment.Type.Move -> {
                 if (!first && !isEmpty) {
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/ColorSpace.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/ColorSpace.kt
index 3905cff..ec0cc69 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/ColorSpace.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/ColorSpace.kt
@@ -633,7 +633,7 @@
  * @param r2: The third element of the vector
  * @return The first element of the resulting multiplication.
  */
-@Suppress("NOTHING_TO_INLINE")
+@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
 internal inline fun mul3x3Float3_0(lhs: FloatArray, r0: Float, r1: Float, r2: Float): Float {
     return lhs[0] * r0 + lhs[3] * r1 + lhs[6] * r2
 }
@@ -648,7 +648,7 @@
  * @param r2: The third element of the vector
  * @return The second element of the resulting multiplication.
  */
-@Suppress("NOTHING_TO_INLINE")
+@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
 internal inline fun mul3x3Float3_1(lhs: FloatArray, r0: Float, r1: Float, r2: Float): Float {
     return lhs[1] * r0 + lhs[4] * r1 + lhs[7] * r2
 }
@@ -663,7 +663,7 @@
  * @param r2: The third element of the vector
  * @return The third element of the resulting multiplication.
  */
-@Suppress("NOTHING_TO_INLINE")
+@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
 internal inline fun mul3x3Float3_2(lhs: FloatArray, r0: Float, r1: Float, r2: Float): Float {
     return lhs[2] * r0 + lhs[5] * r1 + lhs[8] * r2
 }
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Connector.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Connector.kt
index 7a47484..2a81bac 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Connector.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Connector.kt
@@ -230,7 +230,7 @@
                         chromaticAdaptation(
                             Adaptation.Bradford.transform,
                             srcXYZ,
-                            Illuminant.D50Xyz.copyOf()
+                            Illuminant.newD50Xyz()
                         )
                     transform = mul3x3(srcAdaptation, source.transform)
                 }
@@ -240,7 +240,7 @@
                         chromaticAdaptation(
                             Adaptation.Bradford.transform,
                             dstXYZ,
-                            Illuminant.D50Xyz.copyOf()
+                            Illuminant.newD50Xyz()
                         )
                     inverseTransform = inverse3x3(mul3x3(dstAdaptation, destination.transform))
                 }
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Illuminant.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Illuminant.kt
index b3598c3..0bf3461 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Illuminant.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Illuminant.kt
@@ -73,4 +73,6 @@
     val E = WhitePoint(0.33333f, 0.33333f)
 
     internal val D50Xyz = floatArrayOf(0.964212f, 1.0f, 0.825188f)
+
+    internal fun newD50Xyz() = floatArrayOf(0.964212f, 1.0f, 0.825188f)
 }
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Rgb.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Rgb.kt
index 06f2891..e9d3032 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Rgb.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/colorspace/Rgb.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
 
 package androidx.compose.ui.graphics.colorspace
 
@@ -853,10 +853,9 @@
         var result = super.hashCode()
         result = 31 * result + whitePoint.hashCode()
         result = 31 * result + primaries.contentHashCode()
-        result = 31 * result + (if (min != +0.0f) min.toBits() else 0)
-        result = 31 * result + (if (max != +0.0f) max.toBits() else 0)
-        result =
-            (31 * result + if (transferParameters != null) transferParameters.hashCode() else 0)
+        result = 31 * result + (if (min != 0.0f) min.toBits() else 0)
+        result = 31 * result + (if (max != 0.0f) max.toBits() else 0)
+        result = (31 * result + (transferParameters?.hashCode() ?: 0))
         if (transferParameters == null) {
             result = 31 * result + oetfOrig.hashCode()
             result = 31 * result + eotfOrig.hashCode()
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 1a28106..9c3549c 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -495,7 +495,6 @@
     method public androidx.compose.ui.test.SemanticsNodeInteraction assertExists(optional String? errorMessageOnFail);
     method public void assertIsDeactivated(optional String? errorMessageOnFail);
     method public androidx.compose.ui.semantics.SemanticsNode fetchSemanticsNode(optional String? errorMessageOnFail);
-    method public int semanticsId();
   }
 
   public final class SemanticsNodeInteractionCollection {
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index 0e101d0..5ded425 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -497,7 +497,6 @@
     method public androidx.compose.ui.test.SemanticsNodeInteraction assertExists(optional String? errorMessageOnFail);
     method public void assertIsDeactivated(optional String? errorMessageOnFail);
     method public androidx.compose.ui.semantics.SemanticsNode fetchSemanticsNode(optional String? errorMessageOnFail);
-    method public int semanticsId();
   }
 
   public final class SemanticsNodeInteractionCollection {
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.kt
index 63c3346..81f94f3 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction.kt
@@ -147,11 +147,6 @@
         }
     }
 
-    /** Fetch the semantics ID. */
-    fun semanticsId(): Int {
-        return fetchSemanticsNode().id
-    }
-
     private fun fetchOneOrThrow(
         errorMessageOnFail: String? = null,
         skipDeactivatedNodes: Boolean = true
diff --git a/compose/ui/ui-text/proguard-rules.pro b/compose/ui/ui-text/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/ui/ui-text/proguard-rules.pro
+++ b/compose/ui/ui-text/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
index 6418529..209fdb9 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/URLSpanCache.android.kt
@@ -42,8 +42,6 @@
  *
  * See b/253292081.
  */
-// "URL" violates naming guidelines, but that is intentional to match the platform API.
-@Suppress("AcronymName")
 @OptIn(ExperimentalTextApi::class)
 @InternalTextApi
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -54,11 +52,9 @@
     private val linkSpansWithListenerByAnnotation =
         WeakHashMap<AnnotatedString.Range<LinkAnnotation>, ComposeClickableSpan>()
 
-    @Suppress("AcronymName")
     fun toURLSpan(urlAnnotation: UrlAnnotation): URLSpan =
         spansByAnnotation.getOrPut(urlAnnotation) { URLSpan(urlAnnotation.url) }
 
-    @Suppress("AcronymName")
     fun toURLSpan(urlRange: AnnotatedString.Range<LinkAnnotation.Url>): URLSpan =
         urlSpansByAnnotation.getOrPut(urlRange) { URLSpan(urlRange.item.url) }
 
diff --git a/compose/ui/ui-unit/proguard-rules.pro b/compose/ui/ui-unit/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/ui/ui-unit/proguard-rules.pro
+++ b/compose/ui/ui-unit/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Constraints.kt b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Constraints.kt
index 79ba2da..80e1938 100644
--- a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Constraints.kt
+++ b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Constraints.kt
@@ -368,10 +368,16 @@
 private const val MinFocusBits = 16
 private const val MaxAllowedForMinFocusBits = (1 shl (31 - MinFocusBits)) - 2
 
+/** The mask to use for the focused dimension when there is minimal focus. */
+private const val MinFocusMask = 0xFFFF // 64K (16 bits)
+
 /** The number of bits used for the non-focused dimension when there is minimal focus. */
 private const val MinNonFocusBits = 15
 private const val MaxAllowedForMinNonFocusBits = (1 shl (31 - MinNonFocusBits)) - 2
 
+/** The mask to use for the non-focused dimension when there is minimal focus. */
+private const val MinNonFocusMask = 0x7FFF // 32K (15 bits)
+
 /** The number of bits to use for the focused dimension when there is maximal focus. */
 private const val MaxFocusBits = 18
 private const val MaxAllowedForMaxFocusBits = (1 shl (31 - MaxFocusBits)) - 2
@@ -383,6 +389,9 @@
 private const val MaxNonFocusBits = 13
 private const val MaxAllowedForMaxNonFocusBits = (1 shl (31 - MaxNonFocusBits)) - 2
 
+/** The mask to use for the non-focused dimension when there is maximal focus. */
+private const val MaxNonFocusMask = 0x1FFF // 8K (13 bits)
+
 // 0xFFFFFFFE_00000003UL.toLong(), written as a signed value to declare it const
 @PublishedApi internal const val MaxDimensionsAndFocusMask = -0x00000001_FFFFFFFDL
 
@@ -443,35 +452,22 @@
 }
 
 internal fun bitsNeedForSizeUnchecked(size: Int): Int {
-    // We could look at the value of size itself, for instance by doing:
-    // when {
-    //     size < MaxNonFocusMask -> MaxNonFocusBits
-    //     ...
-    // }
-    // but the following solution saves a few instructions by avoiding
-    // multiple moves to load large constants
-    val bits = (size + 1).countLeadingZeroBits()
     return when {
-        bits >= 32 - MaxNonFocusBits -> MaxNonFocusBits
-        bits >= 32 - MinNonFocusBits -> MinNonFocusBits
-        bits >= 32 - MinFocusBits -> MinFocusBits
-        bits >= 32 - MaxFocusBits -> MaxFocusBits
+        size < MaxNonFocusMask -> MaxNonFocusBits
+        size < MinNonFocusMask -> MinNonFocusBits
+        size < MinFocusMask -> MinFocusBits
+        size < MaxFocusMask -> MaxFocusBits
         else -> 255
     }
 }
 
 private inline fun maxAllowedForSize(size: Int): Int {
-    // See comment in bitsNeedForSizeUnchecked()
-    // Note: the return value in every case is `1 shl (31 - bits) - 2`
-    // However, computing the value instead of using constants uses more
-    // instructions, so not worth it
-    val bits = (size + 1).countLeadingZeroBits()
-    if (bits <= 13) throwInvalidConstraintsSizeException(size)
     return when {
-        bits >= 32 - MaxNonFocusBits -> MaxAllowedForMaxNonFocusBits
-        bits >= 32 - MinNonFocusBits -> MaxAllowedForMinNonFocusBits
-        bits >= 32 - MinFocusBits -> MaxAllowedForMinFocusBits
-        else -> MaxAllowedForMaxFocusBits
+        size < MaxNonFocusMask -> MaxAllowedForMaxNonFocusBits
+        size < MinNonFocusMask -> MaxAllowedForMinNonFocusBits
+        size < MinFocusMask -> MaxAllowedForMinFocusBits
+        size < MaxFocusMask -> MaxAllowedForMaxFocusBits
+        else -> throwInvalidConstraintsSizeException(size)
     }
 }
 
diff --git a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Density.kt b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Density.kt
index 5b3e3c5..cbefe8a 100644
--- a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Density.kt
+++ b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Density.kt
@@ -65,7 +65,7 @@
      */
     @Stable
     fun TextUnit.toPx(): Float {
-        check(type == TextUnitType.Sp) { "Only Sp can convert to Px" }
+        checkPrecondition(type == TextUnitType.Sp) { "Only Sp can convert to Px" }
         return toDp().toPx()
     }
 
diff --git a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Dp.kt b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Dp.kt
index a88b3c0..e5cac56 100644
--- a/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Dp.kt
+++ b/compose/ui/ui-unit/src/commonMain/kotlin/androidx/compose/ui/unit/Dp.kt
@@ -83,7 +83,10 @@
         /** Infinite dp dimension. */
         @Stable val Infinity = Dp(Float.POSITIVE_INFINITY)
 
-        /** Constant that means unspecified Dp */
+        /**
+         * Constant that means unspecified Dp. Instead of comparing a [Dp] value to this constant,
+         * consider using [isSpecified] and [isUnspecified] instead.
+         */
         @Stable val Unspecified = Dp(Float.NaN)
     }
 }
diff --git a/compose/ui/ui-util/proguard-rules.pro b/compose/ui/ui-util/proguard-rules.pro
index 67d118b..72f4a6c 100644
--- a/compose/ui/ui-util/proguard-rules.pro
+++ b/compose/ui/ui-util/proguard-rules.pro
@@ -15,7 +15,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 2b88ca8..b2b5534 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -220,9 +220,9 @@
 
 package androidx.compose.ui.autofill {
 
-  public interface Autofill {
-    method public void cancelAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
-    method public void requestAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
+  @Deprecated public interface Autofill {
+    method @Deprecated public void cancelAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
+    method @Deprecated public void requestAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
   }
 
   public abstract class AutofillManager {
@@ -230,64 +230,64 @@
     method public abstract void commit();
   }
 
-  public final class AutofillNode {
-    ctor public AutofillNode(optional java.util.List<? extends androidx.compose.ui.autofill.AutofillType> autofillTypes, optional androidx.compose.ui.geometry.Rect? boundingBox, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit>? onFill);
-    method public java.util.List<androidx.compose.ui.autofill.AutofillType> getAutofillTypes();
-    method public androidx.compose.ui.geometry.Rect? getBoundingBox();
-    method public int getId();
-    method public kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? getOnFill();
-    method public void setBoundingBox(androidx.compose.ui.geometry.Rect?);
-    property public final java.util.List<androidx.compose.ui.autofill.AutofillType> autofillTypes;
-    property public final androidx.compose.ui.geometry.Rect? boundingBox;
-    property public final int id;
-    property public final kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? onFill;
+  @Deprecated public final class AutofillNode {
+    ctor @Deprecated public AutofillNode(optional java.util.List<? extends androidx.compose.ui.autofill.AutofillType> autofillTypes, optional androidx.compose.ui.geometry.Rect? boundingBox, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit>? onFill);
+    method @Deprecated public java.util.List<androidx.compose.ui.autofill.AutofillType> getAutofillTypes();
+    method @Deprecated public androidx.compose.ui.geometry.Rect? getBoundingBox();
+    method @Deprecated public int getId();
+    method @Deprecated public kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? getOnFill();
+    method @Deprecated public void setBoundingBox(androidx.compose.ui.geometry.Rect?);
+    property @Deprecated public final java.util.List<androidx.compose.ui.autofill.AutofillType> autofillTypes;
+    property @Deprecated public final androidx.compose.ui.geometry.Rect? boundingBox;
+    property @Deprecated public final int id;
+    property @Deprecated public final kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? onFill;
   }
 
-  public final class AutofillTree {
-    ctor public AutofillTree();
-    method public java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> getChildren();
-    method public kotlin.Unit? performAutofill(int id, String value);
-    method public operator void plusAssign(androidx.compose.ui.autofill.AutofillNode autofillNode);
-    property public final java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> children;
+  @Deprecated public final class AutofillTree {
+    ctor @Deprecated public AutofillTree();
+    method @Deprecated public java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> getChildren();
+    method @Deprecated public kotlin.Unit? performAutofill(int id, String value);
+    method @Deprecated public operator void plusAssign(androidx.compose.ui.autofill.AutofillNode autofillNode);
+    property @Deprecated public final java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> children;
   }
 
-  public enum AutofillType {
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressAuxiliaryDetails;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressCountry;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressLocality;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressRegion;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressStreet;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateDay;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateFull;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateMonth;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateYear;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDate;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDay;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationMonth;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationYear;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardNumber;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardSecurityCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType EmailAddress;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Gender;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType NewPassword;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType NewUsername;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Password;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonFirstName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonFullName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonLastName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonMiddleInitial;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonMiddleName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonNamePrefix;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonNameSuffix;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneCountryCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumber;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumberDevice;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumberNational;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalAddress;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalCodeExtended;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType SmsOtpCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Username;
+  @Deprecated public enum AutofillType {
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressAuxiliaryDetails;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressCountry;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressLocality;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressRegion;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressStreet;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateDay;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateFull;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateMonth;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateYear;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDate;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDay;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationMonth;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationYear;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardNumber;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardSecurityCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType EmailAddress;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Gender;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType NewPassword;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType NewUsername;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Password;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonFirstName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonFullName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonLastName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonMiddleInitial;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonMiddleName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonNamePrefix;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonNameSuffix;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneCountryCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumber;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumberDevice;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumberNational;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalAddress;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalCodeExtended;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType SmsOtpCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Username;
   }
 
   @kotlin.jvm.JvmInline public final value class ContentDataType {
@@ -3202,9 +3202,9 @@
 
   public final class CompositionLocalsKt {
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.AccessibilityManager?> getLocalAccessibilityManager();
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> getLocalAutofill();
+    method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> getLocalAutofill();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillManager?> getLocalAutofillManager();
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> getLocalAutofillTree();
+    method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> getLocalAutofillTree();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.Clipboard> getLocalClipboard();
     method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ClipboardManager> getLocalClipboardManager();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalCursorBlinkEnabled();
@@ -3223,9 +3223,9 @@
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ViewConfiguration> getLocalViewConfiguration();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.WindowInfo> getLocalWindowInfo();
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.AccessibilityManager?> LocalAccessibilityManager;
-    property @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> LocalAutofill;
+    property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> LocalAutofill;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillManager?> LocalAutofillManager;
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> LocalAutofillTree;
+    property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> LocalAutofillTree;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.Clipboard> LocalClipboard;
     property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ClipboardManager> LocalClipboardManager;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalCursorBlinkEnabled;
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 8b114f0..f381fac 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -220,9 +220,9 @@
 
 package androidx.compose.ui.autofill {
 
-  public interface Autofill {
-    method public void cancelAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
-    method public void requestAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
+  @Deprecated public interface Autofill {
+    method @Deprecated public void cancelAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
+    method @Deprecated public void requestAutofillForNode(androidx.compose.ui.autofill.AutofillNode autofillNode);
   }
 
   public abstract class AutofillManager {
@@ -230,64 +230,64 @@
     method public abstract void commit();
   }
 
-  public final class AutofillNode {
-    ctor public AutofillNode(optional java.util.List<? extends androidx.compose.ui.autofill.AutofillType> autofillTypes, optional androidx.compose.ui.geometry.Rect? boundingBox, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit>? onFill);
-    method public java.util.List<androidx.compose.ui.autofill.AutofillType> getAutofillTypes();
-    method public androidx.compose.ui.geometry.Rect? getBoundingBox();
-    method public int getId();
-    method public kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? getOnFill();
-    method public void setBoundingBox(androidx.compose.ui.geometry.Rect?);
-    property public final java.util.List<androidx.compose.ui.autofill.AutofillType> autofillTypes;
-    property public final androidx.compose.ui.geometry.Rect? boundingBox;
-    property public final int id;
-    property public final kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? onFill;
+  @Deprecated public final class AutofillNode {
+    ctor @Deprecated public AutofillNode(optional java.util.List<? extends androidx.compose.ui.autofill.AutofillType> autofillTypes, optional androidx.compose.ui.geometry.Rect? boundingBox, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit>? onFill);
+    method @Deprecated public java.util.List<androidx.compose.ui.autofill.AutofillType> getAutofillTypes();
+    method @Deprecated public androidx.compose.ui.geometry.Rect? getBoundingBox();
+    method @Deprecated public int getId();
+    method @Deprecated public kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? getOnFill();
+    method @Deprecated public void setBoundingBox(androidx.compose.ui.geometry.Rect?);
+    property @Deprecated public final java.util.List<androidx.compose.ui.autofill.AutofillType> autofillTypes;
+    property @Deprecated public final androidx.compose.ui.geometry.Rect? boundingBox;
+    property @Deprecated public final int id;
+    property @Deprecated public final kotlin.jvm.functions.Function1<java.lang.String,kotlin.Unit>? onFill;
   }
 
-  public final class AutofillTree {
-    ctor public AutofillTree();
-    method public java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> getChildren();
-    method public kotlin.Unit? performAutofill(int id, String value);
-    method public operator void plusAssign(androidx.compose.ui.autofill.AutofillNode autofillNode);
-    property public final java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> children;
+  @Deprecated public final class AutofillTree {
+    ctor @Deprecated public AutofillTree();
+    method @Deprecated public java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> getChildren();
+    method @Deprecated public kotlin.Unit? performAutofill(int id, String value);
+    method @Deprecated public operator void plusAssign(androidx.compose.ui.autofill.AutofillNode autofillNode);
+    property @Deprecated public final java.util.Map<java.lang.Integer,androidx.compose.ui.autofill.AutofillNode> children;
   }
 
-  public enum AutofillType {
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressAuxiliaryDetails;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressCountry;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressLocality;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressRegion;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType AddressStreet;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateDay;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateFull;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateMonth;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType BirthDateYear;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDate;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDay;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationMonth;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationYear;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardNumber;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType CreditCardSecurityCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType EmailAddress;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Gender;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType NewPassword;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType NewUsername;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Password;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonFirstName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonFullName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonLastName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonMiddleInitial;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonMiddleName;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonNamePrefix;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PersonNameSuffix;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneCountryCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumber;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumberDevice;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PhoneNumberNational;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalAddress;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType PostalCodeExtended;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType SmsOtpCode;
-    enum_constant public static final androidx.compose.ui.autofill.AutofillType Username;
+  @Deprecated public enum AutofillType {
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressAuxiliaryDetails;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressCountry;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressLocality;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressRegion;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType AddressStreet;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateDay;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateFull;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateMonth;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType BirthDateYear;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDate;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationDay;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationMonth;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardExpirationYear;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardNumber;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType CreditCardSecurityCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType EmailAddress;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Gender;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType NewPassword;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType NewUsername;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Password;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonFirstName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonFullName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonLastName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonMiddleInitial;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonMiddleName;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonNamePrefix;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PersonNameSuffix;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneCountryCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumber;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumberDevice;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PhoneNumberNational;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalAddress;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType PostalCodeExtended;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType SmsOtpCode;
+    enum_constant @Deprecated public static final androidx.compose.ui.autofill.AutofillType Username;
   }
 
   @kotlin.jvm.JvmInline public final value class ContentDataType {
@@ -3256,9 +3256,9 @@
 
   public final class CompositionLocalsKt {
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.AccessibilityManager?> getLocalAccessibilityManager();
-    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> getLocalAutofill();
+    method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> getLocalAutofill();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillManager?> getLocalAutofillManager();
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> getLocalAutofillTree();
+    method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> getLocalAutofillTree();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.Clipboard> getLocalClipboard();
     method @Deprecated public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ClipboardManager> getLocalClipboardManager();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalCursorBlinkEnabled();
@@ -3277,9 +3277,9 @@
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ViewConfiguration> getLocalViewConfiguration();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.WindowInfo> getLocalWindowInfo();
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.AccessibilityManager?> LocalAccessibilityManager;
-    property @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> LocalAutofill;
+    property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.Autofill?> LocalAutofill;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillManager?> LocalAutofillManager;
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> LocalAutofillTree;
+    property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.autofill.AutofillTree> LocalAutofillTree;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.Clipboard> LocalClipboard;
     property @Deprecated public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.platform.ClipboardManager> LocalClipboardManager;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalCursorBlinkEnabled;
diff --git a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
index d4ba384..6677cd4 100644
--- a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
@@ -41,13 +41,15 @@
 
     @get:Rule val benchmarkRule = BenchmarkRule()
 
-    private lateinit var autofillTree: androidx.compose.ui.autofill.AutofillTree
+    private lateinit var autofillTree:
+        @Suppress("Deprecation")
+        androidx.compose.ui.autofill.AutofillTree
     private lateinit var composeView: View
 
     @Before
     fun setup() {
         composeTestRule.setContent {
-            autofillTree = LocalAutofillTree.current
+            autofillTree = @Suppress("Deprecation") LocalAutofillTree.current
             composeView = LocalView.current
         }
     }
@@ -59,6 +61,7 @@
             composeTestRule.runOnUiThread {
                 // Arrange.
                 val autofillNode =
+                    @Suppress("Deprecation")
                     androidx.compose.ui.autofill.AutofillNode(
                         onFill = {},
                         autofillTypes =
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 73d3551..ed7c760 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -24,7 +24,6 @@
 
 import androidx.build.KotlinTarget
 import androidx.build.LibraryType
-import androidx.build.KmpPlatformsKt
 import androidx.build.PlatformIdentifier
 
 import static androidx.inspection.gradle.InspectionPluginKt.packageInspector
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/ExplicitAutofillTypesDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/ExplicitAutofillTypesDemo.kt
index f9e568a..fdb8704c 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/ExplicitAutofillTypesDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/ExplicitAutofillTypesDemo.kt
@@ -30,7 +30,6 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.layout.boundsInWindow
@@ -49,7 +48,11 @@
 
     Column {
         Autofill(
-            autofillTypes = listOf(androidx.compose.ui.autofill.AutofillType.PersonFullName),
+            autofillTypes =
+                listOf(
+                    @Suppress("Deprecation")
+                    androidx.compose.ui.autofill.AutofillType.PersonFullName
+                ),
             onFill = { name = TextFieldValue(it) }
         ) {
             OutlinedTextField(
@@ -62,7 +65,10 @@
         Spacer(Modifier.height(10.dp))
 
         Autofill(
-            autofillTypes = listOf(androidx.compose.ui.autofill.AutofillType.EmailAddress),
+            autofillTypes =
+                listOf(
+                    @Suppress("Deprecation") androidx.compose.ui.autofill.AutofillType.EmailAddress
+                ),
             onFill = { email = TextFieldValue(it) }
         ) {
             OutlinedTextField(
@@ -76,14 +82,15 @@
 
 @Composable
 private fun Autofill(
-    autofillTypes: List<androidx.compose.ui.autofill.AutofillType>,
+    autofillTypes: List<@Suppress("Deprecation") androidx.compose.ui.autofill.AutofillType>,
     onFill: ((String) -> Unit),
     content: @Composable BoxScope.() -> Unit
 ) {
-    val autofill = @OptIn(ExperimentalComposeUiApi::class) LocalAutofill.current
-    val autofillTree = LocalAutofillTree.current
+    val autofill = @Suppress("Deprecation") LocalAutofill.current
+    val autofillTree = @Suppress("Deprecation") LocalAutofillTree.current
     val autofillNode =
         remember(autofillTypes, onFill) {
+            @Suppress("Deprecation")
             androidx.compose.ui.autofill.AutofillNode(
                 onFill = onFill,
                 autofillTypes = autofillTypes
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/MixedOldNewAutofillDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/MixedOldNewAutofillDemo.kt
index fd19751..5c8044d 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/MixedOldNewAutofillDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/autofill/MixedOldNewAutofillDemo.kt
@@ -32,7 +32,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.remember
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.autofill.ContentType
 import androidx.compose.ui.focus.onFocusChanged
@@ -69,10 +68,11 @@
         )
 
         // Text field using old autofill API.
-        val autofill = @OptIn(ExperimentalComposeUiApi::class) LocalAutofill.current
-        val autofillTree = LocalAutofillTree.current
+        val autofill = @Suppress("DEPRECATION") LocalAutofill.current
+        val autofillTree = @Suppress("DEPRECATION") LocalAutofillTree.current
         val textState = rememberTextFieldState()
         val autofillNode = remember {
+            @Suppress("DEPRECATION")
             androidx.compose.ui.autofill.AutofillNode(
                 onFill = { textState.edit { replace(0, length, it) } },
                 autofillTypes = listOf(androidx.compose.ui.autofill.AutofillType.Password),
diff --git a/compose/ui/ui/proguard-rules.pro b/compose/ui/ui/proguard-rules.pro
index fa5b4c3..36af3b2 100644
--- a/compose/ui/ui/proguard-rules.pro
+++ b/compose/ui/ui/proguard-rules.pro
@@ -35,7 +35,7 @@
 # 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.**.* {
+-keepclassmembers,allowshrinking,allowobfuscation class androidx.compose.**.* {
     static void throw*Exception(...);
     static void throw*ExceptionForNullCheck(...);
     # For methods returning Nothing
@@ -52,3 +52,4 @@
 -keepnames class androidx.compose.ui.input.pointer.PointerInputEventHandler {
     *;
 }
+
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 164d5628..5758c8a 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -149,13 +149,13 @@
 import androidx.compose.ui.semantics.paneTitle
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.semantics.testTagsAsResourceId
 import androidx.compose.ui.semantics.textSelectionRange
 import androidx.compose.ui.semantics.traversalIndex
 import androidx.compose.ui.test.SemanticsMatcher.Companion.expectValue
-import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.assert
 import androidx.compose.ui.test.assertContentDescriptionEquals
@@ -210,6 +210,7 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_TEXT
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_IME_ENTER
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.FOCUS_INPUT
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.RANGE_TYPE_FLOAT
 import androidx.core.view.accessibility.AccessibilityNodeProviderCompat
@@ -306,7 +307,7 @@
                 BasicText("ToggleableText")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -386,7 +387,7 @@
             }
         }
 
-        val passwordFieldId = rule.onNodeWithTag(tag, true).semanticsId
+        val passwordFieldId = rule.onNodeWithTag(tag, true).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(passwordFieldId) }
@@ -423,7 +424,7 @@
                 repeat(5) { DropdownMenuItem(onClick = {}) { Text("Menu Item $it") } }
             }
         }
-        val virtualId = rule.onNodeWithTag(tag, true).semanticsId
+        val virtualId = rule.onNodeWithTag(tag, true).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -452,7 +453,7 @@
                 BasicText("Text")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -483,7 +484,7 @@
                 BasicText("Text")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -516,7 +517,7 @@
                 BasicText("Text")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -545,7 +546,7 @@
                 Text("Filter chip")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -574,7 +575,7 @@
         setContent {
             Box(Modifier.semantics { pageUp { true } }.testTag(tag)) { BasicText("Text") }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -603,7 +604,7 @@
                 BasicText("Text")
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -623,7 +624,7 @@
     fun testCreateAccessibilityNodeInfo_numberPicker_expectedClassName() {
         // Arrange.
         setContent { Box(Modifier.semantics { role = Role.ValuePicker }.testTag(tag)) }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -638,7 +639,7 @@
     fun testCreateAccessibilityNodeInfo_progressIndicator_determinate() {
         // Arrange.
         setContent { Box(Modifier.progressSemantics(0.5f).testTag(tag)) { BasicText("Text") } }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -663,7 +664,7 @@
     fun testCreateAccessibilityNodeInfo_progressIndicator_determinate_indeterminate() {
         // Arrange.
         setContent { Box(Modifier.progressSemantics().testTag(tag)) { BasicText("Text") } }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -691,7 +692,7 @@
                 onValueChange = { value = it }
             )
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -735,7 +736,7 @@
     fun emptyTextField_hasStateDescription() {
         setContent { BasicTextField(rememberTextFieldState(), modifier = Modifier.testTag(tag)) }
 
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
 
         rule.runOnIdle {
@@ -757,7 +758,7 @@
             }
         }
 
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
 
         rule.runOnIdle {
@@ -782,7 +783,7 @@
             )
         }
 
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
 
         rule.runOnIdle { with(info) { assertThat(stateDescription).isNull() } }
@@ -808,7 +809,7 @@
             )
         }
 
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
 
         rule.runOnIdle { with(info) { assertThat(stateDescription).isNull() } }
@@ -819,7 +820,7 @@
         // Arrange.
         val text = "Test"
         setContent { BasicText(text = text) }
-        val virtualId = rule.onNodeWithText(text).semanticsId
+        val virtualId = rule.onNodeWithText(text).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -832,7 +833,7 @@
     fun testCreateAccessibilityNodeInfo_forFocusable_notFocused() {
         // Arrange.
         setContent { Box(Modifier.testTag(tag).focusable()) { BasicText("focusable") } }
-        val virtualId = rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -860,7 +861,7 @@
             }
         }
         rule.runOnIdle { focusRequester.requestFocus() }
-        val virtualId = rule.onNodeWithTag(tag).assert(expectValue(Focused, true)).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).assert(expectValue(Focused, true)).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -921,8 +922,8 @@
                 Row { Text(overlaidText) }
             }
         }
-        val node3VirtualId = rule.onNodeWithText(text3).semanticsId
-        val overlaidNodeVirtualId = rule.onNodeWithText(overlaidText).semanticsId
+        val node3VirtualId = rule.onNodeWithText(text3).semanticsId()
+        val overlaidNodeVirtualId = rule.onNodeWithText(overlaidText).semanticsId()
 
         // Act.
         val ani3 = rule.runOnIdle { createAccessibilityNodeInfo(node3VirtualId) }
@@ -957,8 +958,8 @@
                 Row { Text(overlaidText) }
             }
         }
-        val node3VirtualId = rule.onNodeWithText(text3).semanticsId
-        val overlaidNodeVirtualId = rule.onNodeWithText(overlaidText).semanticsId
+        val node3VirtualId = rule.onNodeWithText(text3).semanticsId()
+        val overlaidNodeVirtualId = rule.onNodeWithText(overlaidText).semanticsId()
 
         // Act.
         val ani3 = rule.runOnIdle { createAccessibilityNodeInfo(node3VirtualId) }
@@ -999,8 +1000,8 @@
                 }
             }
         }
-        val rowVirtualId = rule.onNodeWithTag(clickableRowTag).semanticsId
-        val buttonId = rule.onNodeWithTag(clickableButtonTag).semanticsId
+        val rowVirtualId = rule.onNodeWithTag(clickableRowTag).semanticsId()
+        val buttonId = rule.onNodeWithTag(clickableButtonTag).semanticsId()
 
         // Act.
         val rowANI = rule.runOnIdle { createAccessibilityNodeInfo(rowVirtualId) }
@@ -1047,8 +1048,8 @@
             }
         }
 
-        val titleId = rule.onNodeWithTag(clickableTitle).semanticsId
-        val firstElementId = rule.onNodeWithTag(clickableFirstListElement).semanticsId
+        val titleId = rule.onNodeWithTag(clickableTitle).semanticsId()
+        val firstElementId = rule.onNodeWithTag(clickableFirstListElement).semanticsId()
 
         // Act.
         val titleANI = rule.runOnIdle { createAccessibilityNodeInfo(titleId) }
@@ -1104,10 +1105,10 @@
                 }
             }
         }
-        val topText1 = rule.onNodeWithText(topSampleText + 1).semanticsId
-        val topText2 = rule.onNodeWithText(topSampleText + 2).semanticsId
-        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId
-        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId
+        val topText1 = rule.onNodeWithText(topSampleText + 1).semanticsId()
+        val topText2 = rule.onNodeWithText(topSampleText + 2).semanticsId()
+        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId()
+        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1149,10 +1150,10 @@
                 }
             }
         }
-        val topText1 = rule.onNodeWithText(topSampleText + 1).semanticsId
-        val topText2 = rule.onNodeWithText(topSampleText + 2).semanticsId
-        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId
-        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId
+        val topText1 = rule.onNodeWithText(topSampleText + 1).semanticsId()
+        val topText2 = rule.onNodeWithText(topSampleText + 2).semanticsId()
+        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId()
+        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1197,8 +1198,8 @@
                 }
             }
         }
-        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId
-        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId
+        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId()
+        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId()
 
         // Act.
         val bottomText1ANI = rule.runOnIdle { createAccessibilityNodeInfo(bottomText1) }
@@ -1240,10 +1241,10 @@
                 )
             }
         }
-        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId
-        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId
-        val bottomText3 = rule.onNodeWithText(bottomSampleText + 3).semanticsId
-        val topText3 = rule.onNodeWithText(topSampleText + 3).semanticsId
+        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId()
+        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId()
+        val bottomText3 = rule.onNodeWithText(bottomSampleText + 3).semanticsId()
+        val topText3 = rule.onNodeWithText(topSampleText + 3).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1296,8 +1297,8 @@
                 )
             }
         }
-        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId
-        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId
+        val bottomText1 = rule.onNodeWithText(bottomSampleText + 1).semanticsId()
+        val bottomText2 = rule.onNodeWithText(bottomSampleText + 2).semanticsId()
 
         // Act.
         val bottomText1ANI = rule.runOnIdle { createAccessibilityNodeInfo(bottomText1) }
@@ -1336,8 +1337,8 @@
                 }
             }
         }
-        val node1 = rule.onNodeWithText(text1).semanticsId
-        val overlaidNode = rule.onNodeWithText(overlaidText).semanticsId
+        val node1 = rule.onNodeWithText(text1).semanticsId()
+        val overlaidNode = rule.onNodeWithText(overlaidText).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(overlaidNode) }
@@ -1389,12 +1390,12 @@
                 Row { Text(text = text0) }
             }
         }
-        val virtualViewId0 = rule.onNodeWithText(text0).semanticsId
-        val virtualViewId1 = rule.onNodeWithText(text1).semanticsId
-        val virtualViewId2 = rule.onNodeWithText(text2).semanticsId
-        val virtualViewId3 = rule.onNodeWithText(text3).semanticsId
-        val virtualViewId4 = rule.onNodeWithText(text4).semanticsId
-        val virtualViewId5 = rule.onNodeWithText(text5).semanticsId
+        val virtualViewId0 = rule.onNodeWithText(text0).semanticsId()
+        val virtualViewId1 = rule.onNodeWithText(text1).semanticsId()
+        val virtualViewId2 = rule.onNodeWithText(text2).semanticsId()
+        val virtualViewId3 = rule.onNodeWithText(text3).semanticsId()
+        val virtualViewId4 = rule.onNodeWithText(text4).semanticsId()
+        val virtualViewId5 = rule.onNodeWithText(text5).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1444,8 +1445,8 @@
                 }
             }
         }
-        val node3Id = rule.onNodeWithText(text3).semanticsId
-        val overlayId = rule.onNodeWithText(overlaidText).semanticsId
+        val node3Id = rule.onNodeWithText(text3).semanticsId()
+        val overlayId = rule.onNodeWithText(overlaidText).semanticsId()
 
         // Act.
         val node3ANI = rule.runOnIdle { createAccessibilityNodeInfo(node3Id) }
@@ -1486,8 +1487,8 @@
                 }
             }
         }
-        val node3Id = rule.onNodeWithText(text3).semanticsId
-        val overlayId = rule.onNodeWithText(overlaidText).semanticsId
+        val node3Id = rule.onNodeWithText(text3).semanticsId()
+        val overlayId = rule.onNodeWithText(overlaidText).semanticsId()
 
         // Act.
         val node3ANI = rule.runOnIdle { createAccessibilityNodeInfo(node3Id) }
@@ -1506,8 +1507,8 @@
 
             TopAppBar(title = { Text(text = topAppBarText) })
         }
-        val textBoxId = rule.onNodeWithTag(textBoxTag).semanticsId
-        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId
+        val textBoxId = rule.onNodeWithTag(textBoxTag).semanticsId()
+        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId()
 
         // Act.
         val topAppBarANI = rule.runOnIdle { createAccessibilityNodeInfo(topAppBarId) }
@@ -1530,9 +1531,9 @@
                 repeat(100) { Text(sampleText + counter++) }
             }
         }
-        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId
-        val node1Id = rule.onNodeWithText(sampleText1).semanticsId
-        val node2Id = rule.onNodeWithText(sampleText2).semanticsId
+        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId()
+        val node1Id = rule.onNodeWithText(sampleText1).semanticsId()
+        val node2Id = rule.onNodeWithText(sampleText2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1569,9 +1570,9 @@
                 bottomBar = { BottomAppBar { Text(bottomAppBarText) } }
             )
         }
-        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId
-        val contentId = rule.onNodeWithText(contentText).semanticsId
-        val bottomAppBarId = rule.onNodeWithText(bottomAppBarText).semanticsId
+        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId()
+        val contentId = rule.onNodeWithText(contentText).semanticsId()
+        val bottomAppBarId = rule.onNodeWithText(bottomAppBarText).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1610,9 +1611,9 @@
                 content = { padding -> Text(contentText, modifier = Modifier.padding(padding)) }
             )
         }
-        val face1Id = rule.onNodeWithContentDescription(content1).semanticsId
-        val face3Id = rule.onNodeWithContentDescription(content3).semanticsId
-        val contentId = rule.onNodeWithText(contentText).semanticsId
+        val face1Id = rule.onNodeWithContentDescription(content1).semanticsId()
+        val face3Id = rule.onNodeWithContentDescription(content3).semanticsId()
+        val contentId = rule.onNodeWithText(contentText).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1665,10 +1666,10 @@
                 Box { BasicText("Child Three", Modifier.testTag(childThreeTag)) }
             }
         }
-        val parentBox1Id = rule.onNodeWithTag(parentBox1Tag).semanticsId
-        val childOneId = rule.onNodeWithTag(childOneTag, useUnmergedTree = true).semanticsId
-        val childTwoId = rule.onNodeWithTag(childTwoTag, useUnmergedTree = true).semanticsId
-        val childThreeId = rule.onNodeWithTag(childThreeTag, useUnmergedTree = true).semanticsId
+        val parentBox1Id = rule.onNodeWithTag(parentBox1Tag).semanticsId()
+        val childOneId = rule.onNodeWithTag(childOneTag, useUnmergedTree = true).semanticsId()
+        val childTwoId = rule.onNodeWithTag(childTwoTag, useUnmergedTree = true).semanticsId()
+        val childThreeId = rule.onNodeWithTag(childThreeTag, useUnmergedTree = true).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1727,9 +1728,9 @@
             )
         }
 
-        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId
-        val firstContentId = rule.onNodeWithTag(firstContentText).semanticsId
-        val lastContentId = rule.onNodeWithTag(lastContentText).semanticsId
+        val topAppBarId = rule.onNodeWithText(topAppBarText).semanticsId()
+        val firstContentId = rule.onNodeWithTag(firstContentText).semanticsId()
+        val lastContentId = rule.onNodeWithTag(lastContentText).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1765,8 +1766,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1794,8 +1795,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1825,8 +1826,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1856,8 +1857,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1887,8 +1888,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1 = rule.onNodeWithTag(childTag1).semanticsId
-        val child2 = rule.onNodeWithTag(childTag2).semanticsId
+        val child1 = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2 = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1928,8 +1929,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         val child2ANI = rule.runOnIdle { createAccessibilityNodeInfo(child2Id) }
@@ -1961,8 +1962,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -1997,8 +1998,8 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithTag(childTag1).semanticsId
-        val child2Id = rule.onNodeWithTag(childTag2).semanticsId
+        val child1Id = rule.onNodeWithTag(childTag1).semanticsId()
+        val child2Id = rule.onNodeWithTag(childTag2).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -2044,13 +2045,13 @@
             }
         }
         val root = rule.onNodeWithTag(rootTag).fetchSemanticsNode()
-        val child1Id = rule.onNodeWithText(childText1).semanticsId
-        val child2Id = rule.onNodeWithText(childText2).semanticsId
-        val child3Id = rule.onNodeWithText(childText3).semanticsId
+        val child1Id = rule.onNodeWithText(childText1).semanticsId()
+        val child2Id = rule.onNodeWithText(childText2).semanticsId()
+        val child3Id = rule.onNodeWithText(childText3).semanticsId()
 
-        val rtlChild1Id = rule.onNodeWithText(rtlChildText1).semanticsId
-        val rtlChild2Id = rule.onNodeWithText(rtlChildText2).semanticsId
-        val rtlChild3Id = rule.onNodeWithText(rtlChildText3).semanticsId
+        val rtlChild1Id = rule.onNodeWithText(rtlChildText1).semanticsId()
+        val rtlChild2Id = rule.onNodeWithText(rtlChildText2).semanticsId()
+        val rtlChild3Id = rule.onNodeWithText(rtlChildText3).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -2134,8 +2135,8 @@
             androidComposeView.androidViewsHandler.layoutNodeToHolder[
                     colSemanticsNode.replacedChildren[1].layoutNode]
         checkNotNull(viewHolder)
-        val firstButtonId = rule.onNodeWithText(firstButtonText).semanticsId
-        val lastButtonId = rule.onNodeWithText(lastButtonText).semanticsId
+        val firstButtonId = rule.onNodeWithText(firstButtonText).semanticsId()
+        val lastButtonId = rule.onNodeWithText(lastButtonText).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -2232,9 +2233,9 @@
             androidComposeView.androidViewsHandler.layoutNodeToHolder[
                     colSemanticsNode.replacedChildren[1].layoutNode]
         checkNotNull(viewHolder) // Check that the View exists
-        val firstButtonId = rule.onNodeWithText(firstButtonText).semanticsId
-        val thirdButtonId = rule.onNodeWithText(thirdButtonText).semanticsId
-        val fourthButtonId = rule.onNodeWithText(fourthButtonText).semanticsId
+        val firstButtonId = rule.onNodeWithText(firstButtonText).semanticsId()
+        val thirdButtonId = rule.onNodeWithText(thirdButtonText).semanticsId()
+        val fourthButtonId = rule.onNodeWithText(fourthButtonText).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -2292,14 +2293,14 @@
         assertThat(scrollState.value).isEqualTo(0)
 
         val showOnScreen = android.R.id.accessibilityActionShowOnScreen
-        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId
+        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target1Id, showOnScreen, null)).isTrue()
         }
         rule.mainClock.advanceTimeBy(5000)
         assertThat(scrollState.value).isGreaterThan(99)
 
-        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId
+        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target2Id, showOnScreen, null)).isTrue()
         }
@@ -2329,7 +2330,7 @@
         assertThat(lazyState.firstVisibleItemScrollOffset).isEqualTo(0)
 
         val showOnScreen = android.R.id.accessibilityActionShowOnScreen
-        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId
+        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target1Id, showOnScreen, null)).isTrue()
         }
@@ -2337,7 +2338,7 @@
         assertThat(lazyState.firstVisibleItemIndex).isEqualTo(0)
         assertThat(lazyState.firstVisibleItemScrollOffset).isGreaterThan(99)
 
-        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId
+        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target2Id, showOnScreen, null)).isTrue()
         }
@@ -2383,7 +2384,7 @@
         // influenced by or influencing the parent row.
         // TODO(b/190865803): Is this the ultimate right behavior we want?
         val showOnScreen = android.R.id.accessibilityActionShowOnScreen
-        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId
+        val target1Id = rule.onNodeWithTag(target1Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target1Id, showOnScreen, null)).isTrue()
         }
@@ -2392,7 +2393,7 @@
         assertThat(lazyState.firstVisibleItemScrollOffset).isGreaterThan(99)
         assertThat(parentLazyState.firstVisibleItemScrollOffset).isEqualTo(0)
 
-        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId
+        val target2Id = rule.onNodeWithTag(target2Tag).semanticsId()
         rule.runOnUiThread {
             assertThat(provider.performAction(target2Id, showOnScreen, null)).isTrue()
         }
@@ -2406,7 +2407,8 @@
     fun testPerformAction_focus() {
         // Arrange.
         setContent { Box(Modifier.testTag(tag).focusable()) { BasicText("focusable") } }
-        val virtualViewId = rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId
+        val virtualViewId =
+            rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId()
 
         // Act.
         rule.runOnUiThread {
@@ -2431,7 +2433,7 @@
             }
         }
         rule.runOnIdle { focusRequester.requestFocus() }
-        val virtualViewId = rule.onNodeWithTag(tag).assert(expectValue(Focused, true)).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).assert(expectValue(Focused, true)).semanticsId()
 
         // Act.
         rule.runOnUiThread {
@@ -2454,7 +2456,7 @@
             }
         }
         rule.onNodeWithTag(tag).assertIsDisplayed().assertIsOn()
-        val toggleableNodeId = rule.onNodeWithTag(tag).semanticsId
+        val toggleableNodeId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val actionPerformed =
@@ -2481,7 +2483,7 @@
                 content = { BasicText("ToggleableText") }
             )
         }
-        val toggleableId = rule.onNodeWithTag(tag).assertIsDisplayed().assertIsOn().semanticsId
+        val toggleableId = rule.onNodeWithTag(tag).assertIsDisplayed().assertIsOn().semanticsId()
 
         // Act.
         val actionPerformed =
@@ -2498,7 +2500,7 @@
         setContent {
             BasicTextField(modifier = Modifier.testTag(tag), value = "value", onValueChange = {})
         }
-        val textFieldNodeId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId
+        val textFieldNodeId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId()
 
         // Act.
         val actionPerformed =
@@ -2529,7 +2531,7 @@
                 onValueChange = { value = it }
             )
         }
-        val textFieldId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId
+        val textFieldId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId()
         val argument = Bundle()
         argument.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1)
         argument.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 1)
@@ -2561,7 +2563,7 @@
                 )
             }
         }
-        val textFieldId = rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId
+        val textFieldId = rule.onNodeWithTag(tag).assert(expectValue(Focused, false)).semanticsId()
 
         // Act.
         var actionPerformed =
@@ -2581,6 +2583,48 @@
     }
 
     @Test
+    fun testFindFocus_noInputFocus() {
+        // Arrange.
+        setContent {
+            Row {
+                // No focused item.
+                Box(Modifier.size(10.dp).focusable())
+                Box(Modifier.size(10.dp).focusable())
+            }
+        }
+
+        // Act.
+        val focusedNode = rule.runOnUiThread { provider.findFocus(FOCUS_INPUT) }
+
+        // Assert.
+        assertThat(focusedNode).isNull()
+    }
+
+    @Test
+    fun testFindFocus_hasInputFocus() {
+        // Arrange.
+        val focusRequester = FocusRequester()
+        setContent {
+            Row {
+                // Initially focused item.
+                Box(Modifier.size(10.dp).focusable())
+                Box(Modifier.testTag(tag).focusRequester(focusRequester).focusable()) {
+                    BasicText("focusable")
+                }
+            }
+        }
+        rule.runOnIdle { focusRequester.requestFocus() }
+        val virtualViewId = rule.onNodeWithTag(tag).assert(expectValue(Focused, true)).semanticsId()
+        val expectedNode = provider.createAccessibilityNodeInfo(virtualViewId)
+
+        // Act.
+        val actualNode = rule.runOnUiThread { provider.findFocus(FOCUS_INPUT) }
+
+        // Assert.
+        assertThat(actualNode).isEqualTo(expectedNode)
+    }
+
+    @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @Suppress("DEPRECATION")
     fun testAddExtraDataToAccessibilityNodeInfo_notMerged() {
@@ -2636,7 +2680,7 @@
     fun getSemanticsNodeIdFromExtraData() {
         // Arrange.
         setContent { BasicText("texy") }
-        val textId = rule.onNodeWithText("texy").semanticsId
+        val textId = rule.onNodeWithText("texy").semanticsId()
         val info = AccessibilityNodeInfoCompat.obtain()
         val argument = Bundle()
         val idKey = "androidx.compose.ui.semantics.id"
@@ -2654,7 +2698,7 @@
     fun sendClickedEvent_whenClick() {
         // Arrange.
         setContent { Box(Modifier.clickable(onClick = {}).testTag(tag)) { BasicText("Text") } }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val actionPerformed =
@@ -2684,7 +2728,7 @@
         setContent {
             Box(Modifier.semantics { stateDescription = state }.testTag(tag)) { BasicText("Text") }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).assertValueEquals("state one").semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).assertValueEquals("state one").semanticsId()
 
         // Act.
         rule.runOnIdle { state = "state two" }
@@ -2731,7 +2775,7 @@
                 BasicText("ToggleableText")
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().assertIsOn().semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().assertIsOn().semanticsId()
 
         // Act.
         rule.onNodeWithTag(tag).performClick()
@@ -2785,7 +2829,7 @@
                 }
             }
         }
-        val toggleableVirtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId
+        val toggleableVirtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId()
 
         // Act.
         val actionPerformed =
@@ -2838,7 +2882,7 @@
             }
         }
         val virtualViewId =
-            rule.onNodeWithTag(tag).assertIsDisplayed().assertIsNotSelected().semanticsId
+            rule.onNodeWithTag(tag).assertIsDisplayed().assertIsNotSelected().semanticsId()
 
         // Act.
         rule.onNodeWithTag(tag).performClick()
@@ -2892,7 +2936,7 @@
             }
         }
         val virtualViewId =
-            rule.onNodeWithTag(tag).assertIsDisplayed().assertIsNotSelected().semanticsId
+            rule.onNodeWithTag(tag).assertIsDisplayed().assertIsNotSelected().semanticsId()
 
         // Act.
         rule.onNodeWithTag(tag).performClick()
@@ -2921,7 +2965,7 @@
         // Arrange.
         var current by mutableStateOf(0.5f)
         setContent { Box(Modifier.progressSemantics(current).testTag(tag)) { BasicText("Text") } }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         rule.runOnIdle { current = 0.9f }
@@ -2993,7 +3037,7 @@
             rule
                 .onNodeWithTag(tag)
                 .assert(expectValue(EditableText, AnnotatedString("HELLO")))
-                .semanticsId
+                .semanticsId()
         rule.runOnIdle {
             verify(container, atLeastOnce())
                 .requestSendAccessibilityEvent(eq(androidComposeView), argument.capture())
@@ -3042,7 +3086,7 @@
                 }
             }
         }
-        val columnId = rule.onNodeWithTag(columnTag).semanticsId
+        val columnId = rule.onNodeWithTag(columnTag).semanticsId()
 
         rule.runOnIdle {
             verify(container, atLeastOnce())
@@ -3097,7 +3141,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId()
 
         // TODO(b/272068594): Extra TYPE_WINDOW_CONTENT_CHANGED sent 100ms after setup.
         rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
@@ -3150,7 +3194,7 @@
         // Arrange.
         val text = "h"
         setContent { BasicText(text, Modifier.testTag(tag)) }
-        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).assertIsDisplayed().semanticsId()
 
         // TODO(b/272068594): Extra TYPE_WINDOW_CONTENT_CHANGED sent 100ms after setup.
         rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
@@ -3207,7 +3251,7 @@
                 Box { BasicText("TextNode") }
             }
         }
-        val toggleableId = rule.onNodeWithTag(tag).semanticsId
+        val toggleableId = rule.onNodeWithTag(tag).semanticsId()
         val textNode =
             rule
                 .onNodeWithText("TextNode", useUnmergedTree = true)
@@ -3229,9 +3273,7 @@
 
         rule.runOnUiThread {
             // Directly call onLayoutChange because this guarantees short time.
-            for (i in 1..10) {
-                delegate.onLayoutChange(textNode.layoutNode)
-            }
+            repeat(10) { delegate.onLayoutChange(textNode.layoutNode) }
         }
 
         rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
@@ -3263,7 +3305,7 @@
             }
         }
 
-        val toggleableId = rule.onNodeWithTag(tag).semanticsId
+        val toggleableId = rule.onNodeWithTag(tag).semanticsId()
         val textNode =
             rule
                 .onNodeWithText("TextNode", useUnmergedTree = true)
@@ -3286,7 +3328,7 @@
 
         rule.runOnUiThread {
             // Directly call onLayoutChange because this guarantees short time.
-            for (i in 1..10) {
+            repeat(10) {
                 // layout change for the parent box node
                 delegate.onLayoutChange(textNode.layoutNode.parent!!)
             }
@@ -3320,7 +3362,7 @@
                 BasicText("ToggleableText")
             }
         }
-        val toggleableId = rule.onNodeWithTag(tag).semanticsId
+        val toggleableId = rule.onNodeWithTag(tag).semanticsId()
         val toggleableBounds =
             with(rule.density) { rule.onNodeWithTag(tag).getBoundsInRoot().toRect() }
 
@@ -3353,8 +3395,8 @@
                 }
             }
         }
-        val childOneId = rule.onNodeWithTag(childOneTag).semanticsId
-        val childTwoId = rule.onNodeWithTag(childTwoTag).semanticsId
+        val childOneId = rule.onNodeWithTag(childOneTag).semanticsId()
+        val childTwoId = rule.onNodeWithTag(childTwoTag).semanticsId()
         val overlappedChildNodeBounds =
             with(rule.density) { rule.onNodeWithTag(childTwoTag).getBoundsInRoot().toRect() }
 
@@ -3399,7 +3441,7 @@
 
         assertThat(scrollState.value).isGreaterThan(199)
 
-        val vitrualViewId = rule.onNodeWithTag(tag).semanticsId
+        val vitrualViewId = rule.onNodeWithTag(tag).semanticsId()
         val childNodeBounds =
             with(rule.density) { rule.onNodeWithTag(tag).getBoundsInRoot().toRect() }
         val hitTestedId =
@@ -3500,7 +3542,7 @@
                 Box(Modifier.size(100.dp).clickable {}.testTag(innertag)) { BasicText("") }
             }
         }
-        val outerNodeId = rule.onNodeWithTag(outertag).semanticsId
+        val outerNodeId = rule.onNodeWithTag(outertag).semanticsId()
         val bounds =
             with(rule.density) { rule.onNodeWithTag(innertag, true).getBoundsInRoot().toRect() }
 
@@ -3658,7 +3700,7 @@
                 )
         }
 
-        val virtualViewId = rule.onNodeWithTag(textTag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(textTag).semanticsId()
         val bounds = with(rule.density) { rule.onNodeWithTag(textTag).getBoundsInRoot().toRect() }
         rule.runOnUiThread {
             val hoverEnter =
@@ -3796,9 +3838,9 @@
                 }
             }
         }
-        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId
-        val overlappedChildOneNodeId = rule.onNodeWithTag(childOneTag).semanticsId
-        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId
+        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId()
+        val overlappedChildOneNodeId = rule.onNodeWithTag(childOneTag).semanticsId()
+        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId()
 
         // Assert.
         rule.runOnIdle {
@@ -3824,8 +3866,8 @@
                 }
             }
         }
-        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId
-        val childTwoId = rule.onNodeWithText("Child Two").semanticsId
+        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId()
+        val childTwoId = rule.onNodeWithText("Child Two").semanticsId()
         val childTwoBounds = Rect()
 
         // Act.
@@ -3855,8 +3897,8 @@
                 }
             }
         }
-        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId
-        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId
+        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId()
+        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId()
 
         rule.runOnIdle {
             assertThat(createAccessibilityNodeInfo(parentNodeId).childCount).isEqualTo(2)
@@ -3886,7 +3928,7 @@
                 .onNodeWithTag(tag)
                 .assert(expectValue(SemanticsProperties.PaneTitle, "pane title"))
                 .assertIsDisplayed()
-                .semanticsId
+                .semanticsId()
         rule.runOnIdle {
             verify(container, times(1))
                 .requestSendAccessibilityEvent(
@@ -3929,7 +3971,7 @@
             rule
                 .onNodeWithTag(tag)
                 .assert(expectValue(SemanticsProperties.PaneTitle, "new pane title"))
-                .semanticsId
+                .semanticsId()
         rule.runOnIdle {
             verify(container, times(1))
                 .requestSendAccessibilityEvent(
@@ -4084,7 +4126,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag("node").semanticsId
+        val virtualViewId = rule.onNodeWithTag("node").semanticsId()
 
         var info = AccessibilityNodeInfoCompat.obtain()
         rule.runOnUiThread { info = createAccessibilityNodeInfo(virtualViewId) }
@@ -4122,7 +4164,7 @@
             }
         }
 
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
         var info = AccessibilityNodeInfoCompat.obtain()
         rule.runOnUiThread { info = createAccessibilityNodeInfo(virtualViewId) }
         val rect = Rect()
@@ -4184,8 +4226,8 @@
                 }
             }
         }
-        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId
-        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId
+        val parentNodeId = rule.onNodeWithTag(parentTag).semanticsId()
+        val overlappedChildTwoNodeId = rule.onNodeWithTag(childTwoTag).semanticsId()
 
         rule.runOnIdle {
             assertThat(createAccessibilityNodeInfo(parentNodeId).childCount).isEqualTo(2)
@@ -4215,7 +4257,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithText("text").semanticsId
+        val virtualViewId = rule.onNodeWithText("text").semanticsId()
 
         var info = AccessibilityNodeInfoCompat.obtain()
         rule.runOnUiThread { info = createAccessibilityNodeInfo(virtualViewId) }
@@ -4283,13 +4325,13 @@
                 }
             }
         }
-        val box1Id = rule.onNodeWithTag(tag1).semanticsId
-        val box2Id = rule.onNodeWithTag(tag2).semanticsId
-        val box3Id = rule.onNodeWithTag(tag3).semanticsId
-        val box4Id = rule.onNodeWithTag(tag4).semanticsId
-        val box5Id = rule.onNodeWithTag(tag5).semanticsId
-        val box6Id = rule.onNodeWithTag(tag6, true).semanticsId
-        val box7Id = rule.onNodeWithTag(tag7, true).semanticsId
+        val box1Id = rule.onNodeWithTag(tag1).semanticsId()
+        val box2Id = rule.onNodeWithTag(tag2).semanticsId()
+        val box3Id = rule.onNodeWithTag(tag3).semanticsId()
+        val box4Id = rule.onNodeWithTag(tag4).semanticsId()
+        val box5Id = rule.onNodeWithTag(tag5).semanticsId()
+        val box6Id = rule.onNodeWithTag(tag6, true).semanticsId()
+        val box7Id = rule.onNodeWithTag(tag7, true).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -4324,7 +4366,7 @@
                 }
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualId) }
@@ -4344,7 +4386,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4361,7 +4403,7 @@
                 Box(Modifier.size(100.toDp()).testTag(tag).semantics { contentDescription = "Box" })
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4382,7 +4424,7 @@
                 )
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4408,7 +4450,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4428,7 +4470,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag("Row").semanticsId
+        val virtualViewId = rule.onNodeWithTag("Row").semanticsId()
 
         // Act.
         val info = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4455,7 +4497,7 @@
                     }
                 }
             }
-            val virtualViewId = rule.onNodeWithTag("tag").semanticsId
+            val virtualViewId = rule.onNodeWithTag("tag").semanticsId()
 
             // Act.
             val accessibilityNodeInfo =
@@ -4494,7 +4536,7 @@
                 }
             }
 
-            val virtualViewId = rule.onNodeWithTag("tag").semanticsId
+            val virtualViewId = rule.onNodeWithTag("tag").semanticsId()
 
             // Act.
             val accessibilityNodeInfo =
@@ -4529,7 +4571,7 @@
             }
         }
 
-        val virtualViewId = rule.onNodeWithTag("tag").semanticsId
+        val virtualViewId = rule.onNodeWithTag("tag").semanticsId()
 
         // Act.
         val accessibilityNodeInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4563,7 +4605,7 @@
                     }
                 }
             }
-            val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+            val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
             // Act.
             val accessibilityNodeInfo =
@@ -4597,7 +4639,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val accessibilityNodeInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4633,7 +4675,7 @@
                 }
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val accessibilityNodeInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4879,7 +4921,7 @@
         setContent {
             Column(Modifier.semantics(true) {}) { BasicText("test", Modifier.testTag(tag)) }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId()
 
         // Act.
         val childInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4895,7 +4937,7 @@
         setContent {
             Column(Modifier.semantics(false) {}) { BasicText("test", Modifier.testTag(tag)) }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId()
 
         // Act.
         val childInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4911,7 +4953,7 @@
         setContent {
             Column(Modifier.semantics(false) {}) { Box(Modifier.testTag(tag).size(100.dp)) }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, useUnmergedTree = true).semanticsId()
 
         // Act.
         val childInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4928,7 +4970,7 @@
                 Image(ImageBitmap(100, 100), "Image", Modifier.testTag(tag))
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId()
 
         // Act.
         val imageInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4945,7 +4987,7 @@
                 Image(ImageBitmap(100, 100), "Image", Modifier.testTag(tag))
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId()
 
         // Act.
         val imageInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4966,7 +5008,7 @@
                 )
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag, true).semanticsId()
 
         // Act.
         val imageInfo = rule.runOnIdle { createAccessibilityNodeInfo(virtualViewId) }
@@ -4992,8 +5034,8 @@
                 }
             }
         }
-        val columnId = rule.onNodeWithTag(tagColumn).semanticsId
-        val rowId = rule.onNodeWithTag(tagRow).semanticsId
+        val columnId = rule.onNodeWithTag(tagColumn).semanticsId()
+        val rowId = rule.onNodeWithTag(tagRow).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -5087,12 +5129,12 @@
                 )
             }
         }
-        val parentId = rule.onNodeWithTag("parent").semanticsId
-        val child1Id = rule.onNodeWithTag("child1").semanticsId
-        val child2Id = rule.onNodeWithTag("child2").semanticsId
-        val child3Id = rule.onNodeWithTag("child3").semanticsId
-        val child4Id = rule.onNodeWithTag("child4").semanticsId
-        val child5Id = rule.onNodeWithTag("child5").semanticsId
+        val parentId = rule.onNodeWithTag("parent").semanticsId()
+        val child1Id = rule.onNodeWithTag("child1").semanticsId()
+        val child2Id = rule.onNodeWithTag("child2").semanticsId()
+        val child3Id = rule.onNodeWithTag("child3").semanticsId()
+        val child4Id = rule.onNodeWithTag("child4").semanticsId()
+        val child5Id = rule.onNodeWithTag("child5").semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -5146,10 +5188,10 @@
                 )
             }
         }
-        val parentId = rule.onNodeWithTag("parent").semanticsId
-        val child1Id = rule.onNodeWithTag("child1").semanticsId
-        val child2Id = rule.onNodeWithTag("child2").semanticsId
-        val child3Id = rule.onNodeWithTag("child3").semanticsId
+        val parentId = rule.onNodeWithTag("parent").semanticsId()
+        val child1Id = rule.onNodeWithTag("child1").semanticsId()
+        val child2Id = rule.onNodeWithTag("child2").semanticsId()
+        val child3Id = rule.onNodeWithTag("child3").semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -5176,8 +5218,8 @@
                 BasicText("test", Modifier.testTag("child"))
             }
         }
-        val boxId = rule.onNodeWithTag("box", useUnmergedTree = true).semanticsId
-        val textId = rule.onNodeWithTag("child", useUnmergedTree = true).semanticsId
+        val boxId = rule.onNodeWithTag("box", useUnmergedTree = true).semanticsId()
+        val textId = rule.onNodeWithTag("child", useUnmergedTree = true).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -5200,8 +5242,8 @@
                 BasicText("test", Modifier.testTag("child"))
             }
         }
-        val boxId = rule.onNodeWithTag("box", useUnmergedTree = true).semanticsId
-        val textId = rule.onNodeWithTag("child", useUnmergedTree = true).semanticsId
+        val boxId = rule.onNodeWithTag("box", useUnmergedTree = true).semanticsId()
+        val textId = rule.onNodeWithTag("child", useUnmergedTree = true).semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -5451,10 +5493,6 @@
     Bottom
 }
 
-// TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-private val SemanticsNodeInteraction.semanticsId: Int
-    get() = fetchSemanticsNode().id
-
 // TODO(b/304359126): Move this to AccessibilityEventCompat and use it wherever we use obtain().
 private fun AccessibilityEvent(): android.view.accessibility.AccessibilityEvent {
     return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
index fb3cf39..193b509 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/AndroidComposeViewAccessibilityDelegateCompatTest.kt
@@ -73,6 +73,7 @@
 import androidx.compose.ui.semantics.progressBarRangeInfo
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.setProgress
 import androidx.compose.ui.semantics.setSelection
 import androidx.compose.ui.semantics.setText
@@ -81,7 +82,6 @@
 import androidx.compose.ui.semantics.testTagsAsResourceId
 import androidx.compose.ui.semantics.text
 import androidx.compose.ui.semantics.textSelectionRange
-import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
@@ -143,7 +143,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -174,7 +174,7 @@
         rule.setContentWithAccessibilityEnabled {
             Box(Modifier.size(10.dp).semantics(mergeDescendants = true) { testTag = tag })
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -189,7 +189,7 @@
         rule.setContentWithAccessibilityEnabled {
             Box(Modifier.size(10.dp).semantics(mergeDescendants = false) { testTag = tag })
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -209,7 +209,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -245,7 +245,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -293,7 +293,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -313,7 +313,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -333,7 +333,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -353,7 +353,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -373,7 +373,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -393,7 +393,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -413,7 +413,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -429,7 +429,7 @@
         rule.setContentWithAccessibilityEnabled {
             Box(Modifier.size(10.dp).semantics(mergeDescendants = false) { testTag = tag })
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -445,7 +445,7 @@
         rule.setContentWithAccessibilityEnabled {
             Box(Modifier.size(10.dp).semantics(mergeDescendants = true) { testTag = tag })
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -468,7 +468,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -490,7 +490,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -511,7 +511,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -535,7 +535,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -557,7 +557,7 @@
                 Box(Modifier.semantics { text = AnnotatedString("foo") })
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -578,7 +578,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -600,7 +600,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -620,7 +620,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -650,8 +650,8 @@
                 )
             }
         }
-        val virtualViewId1 = rule.onNodeWithTag(testTag1).semanticsId
-        val virtualViewId2 = rule.onNodeWithTag(testTag2).semanticsId
+        val virtualViewId1 = rule.onNodeWithTag(testTag1).semanticsId()
+        val virtualViewId2 = rule.onNodeWithTag(testTag2).semanticsId()
 
         // Act.
         lateinit var info1: AccessibilityNodeInfoCompat
@@ -680,7 +680,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
         val info1 = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
         dispatchedAccessibilityEvents.clear()
 
@@ -717,7 +717,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -763,7 +763,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -821,7 +821,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -846,7 +846,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -879,7 +879,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -907,7 +907,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -930,7 +930,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -958,7 +958,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -987,7 +987,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -1013,7 +1013,7 @@
                 }
             )
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { androidComposeView.createAccessibilityNodeInfo(virtualViewId) }
@@ -1273,7 +1273,7 @@
                 }
             )
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         rule.runOnIdle { textChanged = true }
@@ -1426,10 +1426,6 @@
             ViewCompat.getAccessibilityDelegate(this)
                 as AndroidComposeViewAccessibilityDelegateCompat
 
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
     // TODO(b/304359126): Move this to AccessibilityEventCompat and use it wherever we use obtain().
     private fun AccessibilityEvent(): AccessibilityEvent =
         if (SDK_INT >= R) {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/CollectionInfoTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/CollectionInfoTest.kt
index a4a05d7..ab7504f 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/CollectionInfoTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/CollectionInfoTest.kt
@@ -38,7 +38,7 @@
 import androidx.compose.ui.semantics.collectionInfo
 import androidx.compose.ui.semantics.collectionItemInfo
 import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
@@ -88,7 +88,7 @@
                 Box(Modifier.size(50.dp).selectable(selected = false, onClick = {}))
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -109,7 +109,7 @@
         rule.setContentWithAccessibilityEnabled {
             LazyColumn(Modifier.testTag(tag)) { items(2) { BasicText("Text") } }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -132,7 +132,7 @@
                 items(2) { BasicText("Text") }
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -153,7 +153,7 @@
         rule.setContentWithAccessibilityEnabled {
             LazyColumn(Modifier.testTag(tag).selectableGroup()) { items(2) { BasicText("Text") } }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -180,7 +180,7 @@
                 items(2) { BasicText("Text") }
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -205,7 +205,7 @@
                 Box(Modifier.size(50.dp).selectable(selected = false, onClick = {}))
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -230,7 +230,7 @@
                 itemsIndexed(listOf("Text", "Text")) { index, item -> BasicText(item + index) }
             }
         }
-        val virtualId = rule.onNodeWithText("Text0").semanticsId
+        val virtualId = rule.onNodeWithText("Text0").semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -254,7 +254,7 @@
                 }
             }
         }
-        val virtualId = rule.onNodeWithText("Text0").semanticsId
+        val virtualId = rule.onNodeWithText("Text0").semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -286,7 +286,7 @@
                 }
             }
         }
-        val virtualId = rule.onNodeWithText("Text0").semanticsId
+        val virtualId = rule.onNodeWithText("Text0").semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -318,7 +318,7 @@
                 }
             }
         }
-        val virtualId = rule.onNodeWithText("Text0").semanticsId
+        val virtualId = rule.onNodeWithText("Text0").semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -347,7 +347,7 @@
                 // items
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -370,7 +370,7 @@
                 Box(Modifier.size(10.dp).selectable(selected = false, onClick = {}))
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -390,7 +390,7 @@
                 // items
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -407,7 +407,7 @@
                 // items
             }
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -441,9 +441,9 @@
                 )
             }
         }
-        val virtualId0 = rule.onNodeWithTag("item0").semanticsId
-        val virtualId1 = rule.onNodeWithTag("item1").semanticsId
-        val virtualId2 = rule.onNodeWithTag("item2").semanticsId
+        val virtualId0 = rule.onNodeWithTag("item0").semanticsId()
+        val virtualId1 = rule.onNodeWithTag("item1").semanticsId()
+        val virtualId2 = rule.onNodeWithTag("item2").semanticsId()
 
         // Act.
         rule.waitForIdle()
@@ -466,7 +466,7 @@
         rule.setContentWithAccessibilityEnabled {
             HorizontalPager(rememberPagerState { pageCount }, Modifier.size(10.dp).testTag(tag)) {}
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -482,7 +482,7 @@
         rule.setContentWithAccessibilityEnabled {
             VerticalPager(rememberPagerState { pageCount }, Modifier.size(10.dp).testTag(tag)) {}
         }
-        val virtualId = rule.onNodeWithTag(tag).semanticsId
+        val virtualId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         val info = rule.runOnIdle { composeView.createAccessibilityNodeInfo(virtualId) }
@@ -491,10 +491,6 @@
         rule.runOnIdle { assertThat(info.collectionInfo.rowCount).isEqualTo(pageCount) }
     }
 
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
     private fun ComposeContentTestRule.setContentWithAccessibilityEnabled(
         content: @Composable () -> Unit
     ) {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt
index 8b1f629..7a5eb34 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/accessibility/ScrollingTest.kt
@@ -47,9 +47,9 @@
 import androidx.compose.ui.semantics.horizontalScrollAxisRange
 import androidx.compose.ui.semantics.scrollBy
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.semantics.verticalScrollAxisRange
-import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
@@ -113,7 +113,7 @@
             }
         }
         rule.mainClock.advanceTimeBy(accessibilityEventLoopIntervalMs)
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
         rule.runOnIdle { dispatchedAccessibilityEvents.clear() }
 
         // Act.
@@ -461,7 +461,7 @@
             )
         }
 
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
         rule.runOnIdle {
             androidComposeView.accessibilityNodeProvider.performAction(
                 virtualViewId,
@@ -499,7 +499,7 @@
             )
         }
 
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
         rule.runOnIdle {
             androidComposeView.accessibilityNodeProvider.performAction(
                 virtualViewId,
@@ -608,10 +608,6 @@
             ViewCompat.getAccessibilityDelegate(this)
                 as AndroidComposeViewAccessibilityDelegateCompat
 
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
     // TODO(b/304359126): Move this to AccessibilityEventCompat and use it wherever we use obtain().
     private fun AccessibilityEvent(): AccessibilityEvent =
         if (SDK_INT >= R) {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/AndroidAutoFillTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/AndroidAutoFillTest.kt
index b3bc836..a89f445 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/AndroidAutoFillTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/AndroidAutoFillTest.kt
@@ -44,16 +44,16 @@
 class AndroidAutoFillTest {
     @get:Rule val rule = createComposeRule()
 
-    private var autofill: Autofill? = null
-    private lateinit var autofillTree: AutofillTree
+    private var autofill: @Suppress("Deprecation") Autofill? = null
+    private lateinit var autofillTree: @Suppress("Deprecation") AutofillTree
     private lateinit var ownerView: View
 
     @Before
     fun setup() {
         rule.setContent {
             ownerView = LocalView.current
-            autofill = LocalAutofill.current
-            autofillTree = LocalAutofillTree.current
+            autofill = @Suppress("Deprecation") LocalAutofill.current
+            autofillTree = @Suppress("Deprecation") LocalAutofillTree.current
         }
     }
 
@@ -81,6 +81,7 @@
         // Arrange.
         val viewStructure: ViewStructure = FakeViewStructure()
         val autofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = {},
                 autofillTypes = listOf(AutofillType.PersonFullName),
@@ -123,6 +124,7 @@
         val expectedValue = "PersonName"
         var autoFilledValue = ""
         val autofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = { autoFilledValue = it },
                 autofillTypes = listOf(AutofillType.PersonFullName),
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/MixedAutofillTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/MixedAutofillTest.kt
index a955f9d..49e1bfd 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/MixedAutofillTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/MixedAutofillTest.kt
@@ -41,6 +41,7 @@
 import androidx.compose.ui.semantics.contentType
 import androidx.compose.ui.semantics.onAutofillText
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -65,9 +66,8 @@
     @get:Rule val rule = createComposeRule()
     private val height = 200.dp
     private val width = 200.dp
-
-    @OptIn(ExperimentalComposeUiApi::class)
-    private val previousFlagValue = ComposeUiFlags.isSemanticAutofillEnabled
+    private val previousFlagValue =
+        @OptIn(ExperimentalComposeUiApi::class) ComposeUiFlags.isSemanticAutofillEnabled
 
     @Before
     fun enableAutofill() {
@@ -124,13 +124,14 @@
     fun populateViewStructure_new_old_sameLayoutNode() {
         // Arrange.
         lateinit var view: View
-        lateinit var autofillTree: AutofillTree
+        lateinit var autofillTree: @Suppress("DEPRECATION") AutofillTree
         val viewStructure: ViewStructure = FakeViewStructure()
-        lateinit var autofillNode: AutofillNode
+        lateinit var autofillNode: @Suppress("DEPRECATION") AutofillNode
         rule.setContent {
             view = LocalView.current
-            autofillTree = LocalAutofillTree.current
+            autofillTree = @Suppress("DEPRECATION") LocalAutofillTree.current
             autofillNode = remember {
+                @Suppress("DEPRECATION")
                 AutofillNode(
                     onFill = {},
                     autofillTypes = listOf(AutofillType.Password),
@@ -203,13 +204,14 @@
     fun populateViewStructure_new_old_differentLayoutNodes() {
         // Arrange.
         lateinit var view: View
-        lateinit var autofillTree: AutofillTree
+        lateinit var autofillTree: @Suppress("DEPRECATION") AutofillTree
         val viewStructure: ViewStructure = FakeViewStructure()
-        lateinit var autofillNode: AutofillNode
+        lateinit var autofillNode: @Suppress("DEPRECATION") AutofillNode
         rule.setContent {
             view = LocalView.current
-            autofillTree = LocalAutofillTree.current
+            autofillTree = @Suppress("DEPRECATION") LocalAutofillTree.current
             autofillNode = remember {
+                @Suppress("DEPRECATION")
                 AutofillNode(
                     onFill = {},
                     autofillTypes = listOf(AutofillType.Password),
@@ -288,14 +290,15 @@
     fun autofill_new_old_sameLayoutNode() {
         // Arrange.
         lateinit var view: View
-        lateinit var autofillTree: AutofillTree
-        lateinit var autofillNode: AutofillNode
+        lateinit var autofillTree: @Suppress("DEPRECATION") AutofillTree
+        lateinit var autofillNode: @Suppress("DEPRECATION") AutofillNode
         lateinit var autoFilledValueNewApi: String
         lateinit var autoFilledValueOldApi: String
         rule.setContent {
             view = LocalView.current
-            autofillTree = LocalAutofillTree.current
+            autofillTree = @Suppress("DEPRECATION") LocalAutofillTree.current
             autofillNode = remember {
+                @Suppress("DEPRECATION")
                 AutofillNode(
                     onFill = { autoFilledValueOldApi = it },
                     autofillTypes = listOf(AutofillType.Password),
@@ -343,14 +346,15 @@
     fun autofill_new_old_differentLayoutNodes() {
         // Arrange.
         lateinit var view: View
-        lateinit var autofillTree: AutofillTree
-        lateinit var autofillNode: AutofillNode
+        lateinit var autofillTree: @Suppress("DEPRECATION") AutofillTree
+        lateinit var autofillNode: @Suppress("DEPRECATION") AutofillNode
         lateinit var autoFilledValueNewApi: String
         lateinit var autoFilledValueOldApi: String
         rule.setContent {
             view = LocalView.current
-            autofillTree = LocalAutofillTree.current
+            autofillTree = @Suppress("DEPRECATION") LocalAutofillTree.current
             autofillNode = remember {
+                @Suppress("DEPRECATION")
                 AutofillNode(
                     onFill = { autoFilledValueOldApi = it },
                     autofillTypes = listOf(AutofillType.Password),
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/PerformAndroidAutofillManagerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/PerformAndroidAutofillManagerTest.kt
index 4d142e5..e82f664 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/PerformAndroidAutofillManagerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/PerformAndroidAutofillManagerTest.kt
@@ -54,12 +54,12 @@
 import androidx.compose.ui.semantics.password
 import androidx.compose.ui.semantics.requestFocus
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.setText
 import androidx.compose.ui.semantics.toggleableState
 import androidx.compose.ui.state.ToggleableState
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.assertTextEquals
-import androidx.compose.ui.test.isEnabled
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.requestFocus
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldStateSemanticAutofillTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldStateSemanticAutofillTest.kt
index c53af64..fa1cdfd 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldStateSemanticAutofillTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldStateSemanticAutofillTest.kt
@@ -33,6 +33,7 @@
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.contentType
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldsSemanticAutofillTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldsSemanticAutofillTest.kt
index 1b5a6e5..bb5a3dc 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldsSemanticAutofillTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/autofill/TextFieldsSemanticAutofillTest.kt
@@ -41,6 +41,7 @@
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.contentType
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.captureToImage
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
index 147a430..0ccc6aa 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/contentcapture/ContentCaptureTest.kt
@@ -47,12 +47,12 @@
 import androidx.compose.ui.semantics.clearTextSubstitution
 import androidx.compose.ui.semantics.isShowingTextSubstitution
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.semantics.setTextSubstitution
 import androidx.compose.ui.semantics.showTextSubstitution
 import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.semantics.text
 import androidx.compose.ui.semantics.textSubstitution
-import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
@@ -585,7 +585,7 @@
                 )
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         val ids = LongArray(1).apply { this[0] = virtualViewId.toLong() }
         val requestsCollector: Consumer<ViewTranslationRequest?> = mock()
@@ -639,7 +639,7 @@
                 )
             }
         }
-        val virtualViewId = rule.onNodeWithTag(tag).semanticsId
+        val virtualViewId = rule.onNodeWithTag(tag).semanticsId()
 
         // Act.
         rule.runOnIdle {
@@ -785,10 +785,6 @@
         }
     }
 
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
     @Composable
     private fun ContentCaptureTestLazyList(listState: LazyListState) {
         val itemCount = 20
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusListenerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusListenerTest.kt
index e1be2f7..12b5593 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusListenerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/focus/FocusListenerTest.kt
@@ -30,6 +30,7 @@
 import androidx.compose.ui.node.requireSemanticsInfo
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadDelegatesTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadDelegatesTest.kt
new file mode 100644
index 0000000..cb5de6d
--- /dev/null
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadDelegatesTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.ui.layout
+
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.movableContentOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.AndroidOwnerExtraAssertionsRule
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class LookaheadDelegatesTest {
+    @get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
+
+    @get:Rule val excessiveAssertions = AndroidOwnerExtraAssertionsRule()
+
+    @Test
+    fun testResetLookaheadPassDelegate() {
+        var placeChild by mutableStateOf(true)
+        var useLookaheadScope by mutableStateOf(true)
+        rule.setContent {
+            val movableContent = remember {
+                movableContentOf {
+                    Row(Modifier.padding(5.dp).requiredSize(200.dp)) {
+                        Box(Modifier.size(100.dp))
+                        Box(Modifier.size(100.dp))
+                        if (!useLookaheadScope) {
+                            Box(Modifier.size(100.dp))
+                        }
+                    }
+                }
+            }
+            Box(
+                Modifier.layout { m, c ->
+                    m.measure(c).run {
+                        layout(width, height) {
+                            if (placeChild) {
+                                place(0, 0)
+                            }
+                        }
+                    }
+                }
+            ) {
+                // Move moveableContent from a parent in LookaheadScope to a parent that is not
+                // in a LookaheadScope.
+                if (useLookaheadScope) {
+                    Box { LookaheadScope { movableContent() } }
+                } else {
+                    movableContent()
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        placeChild = false
+        useLookaheadScope = !useLookaheadScope
+        rule.waitForIdle()
+
+        placeChild = true
+        rule.waitForIdle()
+    }
+}
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 73d5f2c..57eb795 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION")
+
 package androidx.compose.ui.layout
 
 import androidx.activity.ComponentActivity
@@ -1282,6 +1284,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @OptIn(ExperimentalLayoutApi::class)
     @Test
     fun testNestedLookaheadPlacement() {
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/OnGlobalLayoutListenerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/OnGlobalLayoutListenerTest.kt
index 3ba5d10..1bc9aff 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/OnGlobalLayoutListenerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/OnGlobalLayoutListenerTest.kt
@@ -42,6 +42,7 @@
 import androidx.compose.ui.node.requireOwner
 import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.spatial.RelativeLayoutBounds
 import androidx.compose.ui.test.SemanticsMatcher
 import androidx.compose.ui.test.SemanticsNodeInteraction
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
index 2846ab6..e8f8e7d 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
@@ -67,6 +67,7 @@
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsNode
+import androidx.compose.ui.semantics.semanticsId
 import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.TestActivity
 import androidx.compose.ui.test.assertCountEquals
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt
index 4311904..5d7a5ff 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsListenerTest.kt
@@ -42,7 +42,6 @@
 import androidx.compose.ui.node.invalidateSemantics
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -183,7 +182,7 @@
         rule.runOnIdle { addModifier = true }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -220,7 +219,7 @@
         rule.runOnIdle { removeModifier = true }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -248,7 +247,7 @@
         rule.runOnIdle { text = AnnotatedString("text2") }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -281,7 +280,7 @@
         rule.runOnIdle { text = AnnotatedString("text2") }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -319,7 +318,7 @@
         }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -347,7 +346,7 @@
         rule.runOnIdle { text = "text2" }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -376,7 +375,7 @@
         rule.runOnIdle { text = "text3" }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -417,7 +416,7 @@
         rule.runOnIdle { text = "text2" }
 
         // Assert.
-        val semanticsId = rule.onNodeWithTag("item").semanticsId
+        val semanticsId = rule.onNodeWithTag("item").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -455,8 +454,8 @@
         rule.onNodeWithTag("item2").requestFocus()
 
         // Assert.
-        val item1 = rule.onNodeWithTag("item1").semanticsId
-        val item2 = rule.onNodeWithTag("item2").semanticsId
+        val item1 = rule.onNodeWithTag("item1").semanticsId()
+        val item2 = rule.onNodeWithTag("item2").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -497,8 +496,8 @@
         rule.onNodeWithTag("item2").requestFocus()
 
         // Assert.
-        val item1 = rule.onNodeWithTag("item1").semanticsId
-        val item2 = rule.onNodeWithTag("item2").semanticsId
+        val item1 = rule.onNodeWithTag("item1").semanticsId()
+        val item2 = rule.onNodeWithTag("item2").semanticsId()
         rule.runOnIdle {
             if (isSemanticAutofillEnabled) {
                 assertThat(events)
@@ -543,10 +542,6 @@
 
     data class Event<T>(val semanticsId: Int, val prevSemantics: T?, val newSemantics: T?)
 
-    // TODO(b/272068594): Add api to fetch the semantics id from SemanticsNodeInteraction directly.
-    private val SemanticsNodeInteraction.semanticsId: Int
-        get() = fetchSemanticsNode().id
-
     @Composable
     private fun FocusableBox(
         modifier: Modifier = Modifier,
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsTestUtils.kt
similarity index 66%
copy from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
copy to compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsTestUtils.kt
index f3a5276..2f5767c 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/semantics/SemanticsTestUtils.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.navigation.test;
+package androidx.compose.ui.semantics
 
-public enum TestEnum {
-    VALUE_ONE, VALUE_TWO
-}
+import androidx.compose.ui.test.SemanticsNodeInteraction
+
+/** Fetch the id of the semantics node. */
+internal fun SemanticsNodeInteraction.semanticsId(): Int = fetchSemanticsNode().id
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
index dacdc31..cfeedac 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/viewinterop/FocusSearchLeftInteropTest.kt
@@ -47,6 +47,7 @@
 import androidx.compose.ui.test.requestFocus
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -448,6 +449,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 23) // b/387310914 -- flaky on API 21
     fun viewComposableInRow() {
         // Arrange.
         setContent {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
index 680dcbd..4548793 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
@@ -37,7 +37,10 @@
  * @param autofillTree The autofill tree. This will be replaced by a semantic tree (b/138604305).
  */
 @RequiresApi(Build.VERSION_CODES.O)
-internal class AndroidAutofill(val view: View, val autofillTree: AutofillTree) : Autofill {
+internal class AndroidAutofill(
+    val view: View,
+    val autofillTree: @Suppress("Deprecation") AutofillTree
+) : @Suppress("Deprecation") Autofill {
 
     val autofillManager =
         view.context.getSystemService(AutofillManager::class.java)
@@ -50,7 +53,7 @@
             checkPreconditionNotNull(ViewCompatShims.getAutofillId(view)?.toAutofillId())
     }
 
-    override fun requestAutofillForNode(autofillNode: AutofillNode) {
+    override fun requestAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode) {
         val boundingBox =
             autofillNode.boundingBox ?: error("requestAutofill called before onChildPositioned()")
 
@@ -69,7 +72,7 @@
         )
     }
 
-    override fun cancelAutofillForNode(autofillNode: AutofillNode) {
+    override fun cancelAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode) {
         autofillManager.notifyViewExited(view, autofillNode.id)
     }
 }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillType.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillType.android.kt
index cb92103..47e8a57 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillType.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillType.android.kt
@@ -57,6 +57,7 @@
  * Gets the Android specific [AutofillHint][android.view.ViewStructure.setAutofillHints]
  * corresponding to the current [AutofillType].
  */
+@Suppress("Deprecation")
 internal val AutofillType.androidType: String
     get() {
         val androidAutofillType = androidAutofillTypes[this]
@@ -65,6 +66,7 @@
     }
 
 /** Maps each [AutofillType] to one of the autofill hints in [androidx.autofill.HintConstants] */
+@Suppress("Deprecation")
 private val androidAutofillTypes: HashMap<AutofillType, String> =
     hashMapOf(
         AutofillType.EmailAddress to AUTOFILL_HINT_EMAIL_ADDRESS,
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 811066f..54dec05 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -107,6 +107,8 @@
 import androidx.core.view.accessibility.AccessibilityEventCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.FOCUS_INPUT
 import androidx.core.view.accessibility.AccessibilityNodeProviderCompat
 import androidx.lifecycle.Lifecycle
 import kotlin.math.abs
@@ -342,7 +344,9 @@
     private val handler = Handler(Looper.getMainLooper())
     private var nodeProvider = ComposeAccessibilityNodeProvider()
 
+    private var accessibilityFocusedVirtualViewId = InvalidId
     private var focusedVirtualViewId = InvalidId
+    private var currentlyAccessibilityFocusedANI: AccessibilityNodeInfoCompat? = null
     private var currentlyFocusedANI: AccessibilityNodeInfoCompat? = null
     private var sendingFocusAffectingEvent = false
     private val pendingHorizontalScrollEvents = MutableIntObjectMap<ScrollAxisRange>()
@@ -624,7 +628,7 @@
         }
 
         // Manage internal accessibility focus state.
-        if (virtualViewId == focusedVirtualViewId) {
+        if (virtualViewId == accessibilityFocusedVirtualViewId) {
             info.isAccessibilityFocused = true
             info.addAction(AccessibilityActionCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS)
         } else {
@@ -703,6 +707,7 @@
             info.isFocused = semanticsNode.unmergedConfig[SemanticsProperties.Focused]
             if (info.isFocused) {
                 info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS)
+                focusedVirtualViewId = virtualViewId
             } else {
                 info.addAction(AccessibilityNodeInfoCompat.ACTION_FOCUS)
             }
@@ -1104,7 +1109,7 @@
      * @return True if the view is accessibility focused.
      */
     private fun isAccessibilityFocused(virtualViewId: Int): Boolean {
-        return (focusedVirtualViewId == virtualViewId)
+        return (accessibilityFocusedVirtualViewId == virtualViewId)
     }
 
     /**
@@ -1125,15 +1130,15 @@
         // TODO: Check virtual view visibility.
         if (!isAccessibilityFocused(virtualViewId)) {
             // Clear focus from the previously focused view, if applicable.
-            if (focusedVirtualViewId != InvalidId) {
+            if (accessibilityFocusedVirtualViewId != InvalidId) {
                 sendEventForVirtualView(
-                    focusedVirtualViewId,
+                    accessibilityFocusedVirtualViewId,
                     AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
                 )
             }
 
             // Set focus on the new view.
-            focusedVirtualViewId = virtualViewId
+            accessibilityFocusedVirtualViewId = virtualViewId
             // TODO(b/272068594): Do we have to set currentlyFocusedANI object too?
 
             view.invalidate()
@@ -1265,8 +1270,8 @@
      */
     private fun clearAccessibilityFocus(virtualViewId: Int): Boolean {
         if (isAccessibilityFocused(virtualViewId)) {
-            focusedVirtualViewId = InvalidId
-            currentlyFocusedANI = null
+            accessibilityFocusedVirtualViewId = InvalidId
+            currentlyAccessibilityFocusedANI = null
             view.invalidate()
             sendEventForVirtualView(
                 virtualViewId,
@@ -2496,6 +2501,20 @@
 
                 // Refresh the current "green box" bounds and invalidate the View to tell
                 // ViewRootImpl to redraw it at its latest position.
+                currentSemanticsNodes[accessibilityFocusedVirtualViewId]?.let {
+                    try {
+                        currentlyAccessibilityFocusedANI?.setBoundsInScreen(boundsInScreen(it))
+                    } catch (e: IllegalStateException) {
+                        // setBoundsInScreen could in theory throw an IllegalStateException if the
+                        // system has previously sealed the AccessibilityNodeInfo.  This cannot
+                        // happen on stock AOSP, because ViewRootImpl only uses it for bounds
+                        // checking, and never forwards it to an accessibility service. But that is
+                        // a non-CTS-enforced implementation detail, so we should avoid crashing if
+                        // this happens.
+                    }
+                }
+                // Refresh the current "blue box" bounds and invalidate the View to tell
+                // ViewRootImpl to redraw it at its latest position.
                 currentSemanticsNodes[focusedVirtualViewId]?.let {
                     try {
                         currentlyFocusedANI?.setBoundsInScreen(boundsInScreen(it))
@@ -2820,8 +2839,13 @@
     private inner class ComposeAccessibilityNodeProvider : AccessibilityNodeProviderCompat() {
         override fun createAccessibilityNodeInfo(virtualViewId: Int): AccessibilityNodeInfoCompat? {
             return createNodeInfo(virtualViewId).also {
-                if (sendingFocusAffectingEvent && virtualViewId == focusedVirtualViewId) {
-                    currentlyFocusedANI = it
+                if (sendingFocusAffectingEvent) {
+                    if (virtualViewId == accessibilityFocusedVirtualViewId) {
+                        currentlyAccessibilityFocusedANI = it
+                    }
+                    if (virtualViewId == focusedVirtualViewId) {
+                        currentlyFocusedANI = it
+                    }
                 }
             }
         }
@@ -2840,7 +2864,15 @@
         }
 
         override fun findFocus(focus: Int): AccessibilityNodeInfoCompat? {
-            return createAccessibilityNodeInfo(focusedVirtualViewId)
+            return when (focus) {
+                // TODO(b/364744967): add test for  FOCUS_ACCESSIBILITY
+                FOCUS_ACCESSIBILITY ->
+                    createAccessibilityNodeInfo(accessibilityFocusedVirtualViewId)
+                FOCUS_INPUT ->
+                    if (focusedVirtualViewId == InvalidId) null
+                    else createAccessibilityNodeInfo(focusedVirtualViewId)
+                else -> throw IllegalArgumentException("Unknown focus type: $focus")
+            }
         }
     }
 
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidAutofillTypeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidAutofillTypeTest.kt
index b5c8886..bc1dca0 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidAutofillTypeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidAutofillTypeTest.kt
@@ -21,6 +21,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
+@Suppress("Deprecation")
 @RunWith(JUnit4::class)
 class AndroidAutofillTypeTest {
 
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPerformAutofillTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPerformAutofillTest.kt
index 126bfc9..3b25b9d 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPerformAutofillTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPerformAutofillTest.kt
@@ -32,7 +32,7 @@
 @RunWith(RobolectricTestRunner::class)
 @Config(minSdk = 26)
 class AndroidPerformAutofillTest {
-    private val autofillTree = AutofillTree()
+    private val autofillTree = @Suppress("Deprecation") AutofillTree()
     private lateinit var androidAutofill: AndroidAutofill
 
     @Before
@@ -50,6 +50,7 @@
         val expectedValue = "Name"
         var autoFilledValue = ""
         val autofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = { autoFilledValue = it },
                 autofillTypes = listOf(AutofillType.PersonFullName),
@@ -75,6 +76,7 @@
         val expectedValue = "email@google.com"
         var autoFilledValue = ""
         val autofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = { autoFilledValue = it },
                 autofillTypes = listOf(AutofillType.EmailAddress),
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPopulateViewStructureTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPopulateViewStructureTest.kt
index af54aa9..bfba901 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPopulateViewStructureTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AndroidPopulateViewStructureTest.kt
@@ -32,7 +32,7 @@
 @RunWith(RobolectricTestRunner::class)
 @Config(manifest = Config.NONE, minSdk = 26)
 class AndroidPopulateViewStructureTest {
-    private val autofillTree = AutofillTree()
+    private val autofillTree = @Suppress("Deprecation") AutofillTree()
     private lateinit var androidAutofill: AndroidAutofill
     private lateinit var currentPackage: String
 
@@ -62,6 +62,7 @@
     fun populateViewStructure_oneChild() {
         // Arrange.
         val autofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = {},
                 autofillTypes = listOf(AutofillType.PersonFullName),
@@ -94,6 +95,7 @@
     fun populateViewStructure_twoChildren() {
         // Arrange.
         val nameAutofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = {},
                 autofillTypes = listOf(AutofillType.PersonFullName),
@@ -102,6 +104,7 @@
         autofillTree += nameAutofillNode
 
         val emailAutofillNode =
+            @Suppress("Deprecation")
             AutofillNode(
                 onFill = {},
                 autofillTypes = listOf(AutofillType.EmailAddress),
diff --git a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AutofillNodeTest.kt b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AutofillNodeTest.kt
index debfc97..beef42e 100644
--- a/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AutofillNodeTest.kt
+++ b/compose/ui/ui/src/androidUnitTest/kotlin/androidx/compose/ui/autofill/AutofillNodeTest.kt
@@ -39,7 +39,7 @@
     private lateinit var androidAutofill: AndroidAutofill
     private lateinit var autofillManager: ShadowAutofillManager
     private lateinit var view: View
-    private val autofillTree = AutofillTree()
+    private val autofillTree = @Suppress("Deprecation") AutofillTree()
 
     @Before
     fun setup() {
@@ -57,6 +57,7 @@
 
     @Test
     fun eachInstanceHasUniqueId() {
+        @Suppress("Deprecation")
         assertThat(listOf(AutofillNode {}.id, AutofillNode {}.id, AutofillNode {}.id))
             .containsNoDuplicates()
     }
@@ -70,7 +71,7 @@
     fun requestAutofillForNode_calls_notifyViewEntered() {
         // Arrange.
         val bounds = Rect(0f, 0f, 0f, 0f)
-        val autofillNode = AutofillNode(onFill = {}, boundingBox = bounds)
+        val autofillNode = @Suppress("Deprecation") AutofillNode(onFill = {}, boundingBox = bounds)
 
         // Act.
         androidAutofill.requestAutofillForNode(autofillNode)
@@ -83,7 +84,7 @@
     @Test
     fun requestAutofillForNode_beforeComposableIsPositioned_throwsError() {
         // Arrange - Before the composable is positioned, the boundingBox is null.
-        val autofillNode = AutofillNode(onFill = {})
+        val autofillNode = @Suppress("Deprecation") AutofillNode(onFill = {})
 
         // Act and assert.
         val exception =
@@ -100,7 +101,7 @@
     @Test
     fun cancelAutofillForNode_calls_notifyViewExited() {
         // Arrange.
-        val autofillNode = AutofillNode(onFill = {})
+        val autofillNode = @Suppress("Deprecation") AutofillNode(onFill = {})
 
         // Act.
         androidAutofill.cancelAutofillForNode(autofillNode)
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/ComposeUiFlags.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/ComposeUiFlags.kt
index d1c4c32..dd3946e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/ComposeUiFlags.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/ComposeUiFlags.kt
@@ -75,11 +75,10 @@
     var NewNestedScrollFlingDispatchingEnabled: Boolean = true
 
     /**
-     * With this flag on, the new semantic version of Autofill will be enabled. Prior to the
-     * semantics refactoring, this will introduce significant overhead, but can be used to test out
-     * the new Autofill APIs and features introduced.
+     * With this flag on, the new semantic version of Autofill APIs will be enabled. Turning this
+     * flag off will disable the new Semantic Autofill APIs, and the new refactored semantics.
      */
-    @Suppress("MutableBareField") @JvmField var isSemanticAutofillEnabled: Boolean = false
+    @Suppress("MutableBareField") @JvmField var isSemanticAutofillEnabled: Boolean = true
 
     /**
      * This enables fixes for View focus. The changes are large enough to require a flag to allow
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
index bc0ac620..fd42810 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/Autofill.kt
@@ -30,6 +30,14 @@
  * request or cancel autofill as required. For instance, the TextField can call
  * [requestAutofillForNode] when it gains focus, and [cancelAutofillForNode] when it loses focus.
  */
+@Deprecated(
+    """
+        You no longer have to call these apis when focus changes. They will be called
+        automatically when you Use the new semantics based APIs for autofill. Use the
+        androidx.compose.ui.autofill.ContentType and androidx.compose.ui.autofill.ContentDataType
+        semantics properties instead.
+        """
+)
 interface Autofill {
 
     /**
@@ -37,22 +45,22 @@
      *
      * @param autofillNode The node that needs to be auto-filled.
      *
-     * This function is usually called when an autofillable component gains focus.
+     * This function is usually called when an autofill-able component gains focus.
      */
-    fun requestAutofillForNode(autofillNode: AutofillNode)
+    fun requestAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode)
 
     /**
      * Cancel a previously supplied autofill request.
      *
      * @param autofillNode The node that needs to be auto-filled.
      *
-     * This function is usually called when an autofillable component loses focus.
+     * This function is usually called when an autofill-able component loses focus.
      */
-    fun cancelAutofillForNode(autofillNode: AutofillNode)
+    fun cancelAutofillForNode(autofillNode: @Suppress("Deprecation") AutofillNode)
 }
 
 /**
- * Every autofillable composable will have an [AutofillNode]. (An autofill node will be created for
+ * Every autofill-able composable will have an [AutofillNode]. (An autofill node will be created for
  * every semantics node that adds autofill properties). This node is used to request/cancel
  * autofill, and it holds the [onFill] lambda which is called by the autofill framework.
  *
@@ -67,8 +75,14 @@
  * @property onFill The callback that is called by the autofill framework to perform autofill.
  * @property id A virtual id that is automatically generated for each node.
  */
+@Deprecated(
+    """
+        Use the new semantics-based Autofill APIs androidx.compose.ui.autofill.ContentType and
+        androidx.compose.ui.autofill.ContentDataType instead.
+        """
+)
 class AutofillNode(
-    val autofillTypes: List<AutofillType> = listOf(),
+    val autofillTypes: List<@Suppress("Deprecation") AutofillType> = listOf(),
     var boundingBox: Rect? = null,
     val onFill: ((String) -> Unit)?
 ) {
@@ -87,7 +101,7 @@
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
-        if (other !is AutofillNode) return false
+        if (other !is @Suppress("Deprecation") AutofillNode) return false
 
         if (autofillTypes != other.autofillTypes) return false
         if (boundingBox != other.boundingBox) return false
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillManager.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillManager.kt
index f5ebdc7..a57c432 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillManager.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillManager.kt
@@ -39,7 +39,7 @@
      *
      * Call this function to notify the Autofill framework that the current session should be
      * canceled. After calling this function, the framework will stop the current autofill session
-     * without processing any information entered in the autofillable field.
+     * without processing any information entered in the autofill-able field.
      */
     abstract fun cancel()
 }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillTree.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillTree.kt
index ead55c5..5ed237c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillTree.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillTree.kt
@@ -27,12 +27,18 @@
  * Since this is a temporary implementation, it is implemented as a list of [children], which is
  * essentially a tree of height = 1
  */
+@Deprecated(
+    """
+        Use the new semantics-based Autofill APIs androidx.compose.ui.autofill.ContentType and
+        androidx.compose.ui.autofill.ContentDataType instead.
+        """
+)
 class AutofillTree {
-    /** A map which contains [AutofillNode]s, where every node represents an autofillable field. */
-    val children: MutableMap<Int, AutofillNode> = mutableMapOf()
+    /** A map which contains [AutofillNode]s, where every node represents an autofill-able field. */
+    val children: MutableMap<Int, @Suppress("Deprecation") AutofillNode> = mutableMapOf()
 
     /** Add the specified [AutofillNode] to the [AutofillTree]. */
-    operator fun plusAssign(autofillNode: AutofillNode) {
+    operator fun plusAssign(autofillNode: @Suppress("Deprecation") AutofillNode) {
         children[autofillNode.id] = autofillNode
     }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillType.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillType.kt
index 8449d95..957ec86 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillType.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/autofill/AutofillType.kt
@@ -24,7 +24,11 @@
  * Autofill services use the [AutofillType] to determine what value to use to autofill fields
  * associated with this type. If the [AutofillType] is not specified, the autofill services have to
  * use heuristics to determine the right value to use while auto-filling the corresponding field.
+ *
+ * This has been deprecated in favor of a new semantics based API. Use
+ * [ContentType][androidx.compose.ui.semantics.SemanticsProperties.ContentType] instead.
  */
+@Deprecated("Use the new semantics-based API and androidx.compose.ui.autofill.ContentType instead.")
 enum class AutofillType {
     /** Indicates that the associated component can be auto-filled with an email address. */
     EmailAddress,
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index ef5efb6..1ce3b5b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -118,6 +118,12 @@
                 if (newRoot != null) {
                     layoutDelegate.ensureLookaheadDelegateCreated()
                     forEachCoordinatorIncludingInner { it.ensureLookaheadDelegateCreated() }
+                } else {
+                    // When lookahead root is set to null, clear the lookahead pass delegate.
+                    // This can happen when lookaheadScope is removed in one of the parents, or
+                    // more likely when movableContent moves from a parent in a LookaheadScope to
+                    // a parent not in a LookaheadScope.
+                    layoutDelegate.clearLookaheadDelegate()
                 }
                 invalidateMeasurements()
             }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
index cb30258..65d8e99 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
@@ -368,6 +368,10 @@
         measurePassDelegate.childDelegatesDirty = true
         lookaheadPassDelegate?.let { it.childDelegatesDirty = true }
     }
+
+    fun clearLookaheadDelegate() {
+        lookaheadPassDelegate = null
+    }
 }
 
 /**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index ee7342a..7e031fd 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:Suppress("DEPRECATION")
 
 package androidx.compose.ui.node
 
@@ -21,9 +20,7 @@
 import androidx.collection.IntObjectMap
 import androidx.compose.runtime.Applier
 import androidx.compose.ui.InternalComposeUiApi
-import androidx.compose.ui.autofill.Autofill
 import androidx.compose.ui.autofill.AutofillManager
-import androidx.compose.ui.autofill.AutofillTree
 import androidx.compose.ui.draganddrop.DragAndDropManager
 import androidx.compose.ui.focus.FocusDirection
 import androidx.compose.ui.focus.FocusOwner
@@ -41,7 +38,6 @@
 import androidx.compose.ui.modifier.ModifierLocalManager
 import androidx.compose.ui.platform.AccessibilityManager
 import androidx.compose.ui.platform.Clipboard
-import androidx.compose.ui.platform.ClipboardManager
 import androidx.compose.ui.platform.PlatformTextInputModifierNode
 import androidx.compose.ui.platform.PlatformTextInputSessionScope
 import androidx.compose.ui.platform.SoftwareKeyboardController
@@ -52,7 +48,6 @@
 import androidx.compose.ui.spatial.RectManager
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.input.TextInputService
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.LayoutDirection
@@ -88,7 +83,7 @@
     val inputModeManager: InputModeManager
 
     /** Provide clipboard manager to the user. Use the Android version of clipboard manager. */
-    val clipboardManager: ClipboardManager
+    val clipboardManager: @Suppress("Deprecation") androidx.compose.ui.platform.ClipboardManager
 
     /**
      * Provide clipboard manager with suspend function to the user. Use the Android version of
@@ -114,17 +109,14 @@
     /**
      * A data structure used to store autofill information. It is used by components that want to
      * provide autofill semantics.
-     *
-     * TODO(ralu): Replace with SemanticsTree. This is a temporary hack until we have a semantics
-     *   tree implemented.
      */
-    val autofillTree: AutofillTree
+    val autofillTree: @Suppress("Deprecation") androidx.compose.ui.autofill.AutofillTree
 
     /**
-     * The [Autofill] class can be used to perform autofill operations. It is used as a
-     * CompositionLocal.
+     * The [Autofill][androidx.compose.ui.autofill.Autofill] class can be used to perform autofill
+     * operations. It is used as a CompositionLocal.
      */
-    val autofill: Autofill?
+    val autofill: @Suppress("Deprecation") androidx.compose.ui.autofill.Autofill?
 
     /**
      * The [AutofillManager] class can be used to perform autofill operations. It is used as a
@@ -134,7 +126,7 @@
 
     val density: Density
 
-    val textInputService: TextInputService
+    val textInputService: @Suppress("Deprecation") androidx.compose.ui.text.input.TextInputService
 
     val softwareKeyboardController: SoftwareKeyboardController
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
index f4fa22c..421ffde 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/CompositionLocals.kt
@@ -52,9 +52,12 @@
  * The CompositionLocal that can be used to trigger autofill actions. Eg.
  * [Autofill.requestAutofillForNode].
  */
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-@get:ExperimentalComposeUiApi
-@ExperimentalComposeUiApi
+@Deprecated(
+    """
+        Use the new semantics-based Autofill APIs androidx.compose.ui.autofill.ContentType and
+        androidx.compose.ui.autofill.ContentDataType instead.
+        """
+)
 val LocalAutofill = staticCompositionLocalOf<Autofill?> { null }
 
 /**
@@ -62,14 +65,18 @@
  * androidx.compose.ui.autofill.AutofillNode]s to the autofill tree. The [AutofillTree] is a
  * temporary data structure that will be replaced by Autofill Semantics (b/138604305).
  */
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+@Deprecated(
+    """
+        Use the new semantics-based Autofill APIs androidx.compose.ui.autofill.ContentType and
+        androidx.compose.ui.autofill.ContentDataType instead.
+        """
+)
 val LocalAutofillTree =
     staticCompositionLocalOf<AutofillTree> { noLocalProvidedFor("LocalAutofillTree") }
 
 /**
  * The CompositionLocal that can be used to trigger autofill actions. Eg. [AutofillManager.commit].
  */
-@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
 val LocalAutofillManager =
     staticCompositionLocalOf<AutofillManager?> { noLocalProvidedFor("LocalAutofillManager") }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/spatial/RectList.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/spatial/RectList.kt
index 259ae65..ee5c718 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/spatial/RectList.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/spatial/RectList.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
 
 package androidx.compose.ui.spatial
 
@@ -98,19 +98,23 @@
      * keep this in mind if you call this method and have cached any of those values in a local
      * variable, you may need to refresh them.
      */
-    internal fun allocateItemsIndex(): Int {
+    private inline fun allocateItemsIndex(): Int {
         val currentItems = items
         val currentSize = itemsSize
         itemsSize = currentSize + LongsPerItem
         val actualSize = currentItems.size
         if (actualSize <= currentSize + LongsPerItem) {
-            val newSize = max(actualSize * 2, currentSize + LongsPerItem)
-            items = currentItems.copyOf(newSize)
-            stack = stack.copyOf(newSize)
+            resizeStorage(actualSize, currentSize, currentItems)
         }
         return currentSize
     }
 
+    private fun resizeStorage(actualSize: Int, currentSize: Int, currentItems: LongArray) {
+        val newSize = max(actualSize * 2, currentSize + LongsPerItem)
+        items = currentItems.copyOf(newSize)
+        stack = stack.copyOf(newSize)
+    }
+
     /**
      * Insert a value and corresponding bounding rectangle into the RectList. This method does not
      * check to see that [value] doesn't already exist somewhere in the list.
diff --git a/constraintlayout/constraintlayout-core/build.gradle b/constraintlayout/constraintlayout-core/build.gradle
index a2570c0..8826adc 100644
--- a/constraintlayout/constraintlayout-core/build.gradle
+++ b/constraintlayout/constraintlayout-core/build.gradle
@@ -29,6 +29,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api("androidx.annotation:annotation:1.8.1")
     testImplementation(libs.junit)
 }
@@ -39,6 +40,4 @@
     mavenVersion = LibraryVersions.CONSTRAINTLAYOUT_CORE
     inceptionYear = "2022"
     description = "This library contains engines and algorithms for constraint based layout and complex animations (it is used by the ConstraintLayout library)"
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLContainer.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLContainer.java
index f3a66d0..9791396 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLContainer.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLContainer.java
@@ -15,7 +15,7 @@
  */
 package androidx.constraintlayout.core.parser;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 import java.util.ArrayList;
 import java.util.Objects;
@@ -352,9 +352,8 @@
         return null;
     }
 
-    @NonNull
     @Override
-    public CLContainer clone() {
+    public @NonNull CLContainer clone() {
         CLContainer clone = (CLContainer) super.clone();
         ArrayList<CLElement> clonedArray = new ArrayList<>(mElements.size());
         for (CLElement element: mElements) {
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLElement.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLElement.java
index acb7a97..f8badbf 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLElement.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLElement.java
@@ -15,7 +15,7 @@
  */
 package androidx.constraintlayout.core.parser;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -204,9 +204,8 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public CLElement clone() {
+    public @NonNull CLElement clone() {
         try {
             return (CLElement) super.clone();
         } catch (CloneNotSupportedException e) {
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLObject.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLObject.java
index 479edae..49cdbfa 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLObject.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLObject.java
@@ -15,7 +15,7 @@
  */
 package androidx.constraintlayout.core.parser;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 import java.util.Iterator;
 
@@ -106,9 +106,8 @@
         }
     }
 
-    @NonNull
     @Override
-    public CLObject clone() {
+    public @NonNull CLObject clone() {
         // Overriding to get expected return type
         return (CLObject) super.clone();
     }
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLString.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLString.java
index 5ce2fd4..173657f 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLString.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/parser/CLString.java
@@ -15,7 +15,7 @@
  */
 package androidx.constraintlayout.core.parser;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * {@link CLElement} implementation for json Strings when used as property values or array elements.
@@ -34,8 +34,7 @@
     /**
      * Creates a {@link CLString} element from a String object.
      */
-    @NonNull
-    public static CLString from(@NonNull String content) {
+    public static @NonNull CLString from(@NonNull String content) {
         CLString stringElement = new CLString(content.toCharArray());
         stringElement.setStart(0L);
         stringElement.setEnd(content.length() - 1);
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintReference.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintReference.java
index 53e09a9..facf8ac 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintReference.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintReference.java
@@ -20,13 +20,14 @@
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.UNKNOWN;
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.VERTICAL;
 
-import androidx.annotation.Nullable;
 import androidx.constraintlayout.core.motion.utils.TypedBundle;
 import androidx.constraintlayout.core.motion.utils.TypedValues;
 import androidx.constraintlayout.core.state.helpers.Facade;
 import androidx.constraintlayout.core.widgets.ConstraintAnchor;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 
+import org.jspecify.annotations.Nullable;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintSetParser.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintSetParser.java
index efd960d..1cf37f2 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintSetParser.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/ConstraintSetParser.java
@@ -22,7 +22,6 @@
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.HORIZONTAL;
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.VERTICAL;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.constraintlayout.core.motion.utils.TypedBundle;
 import androidx.constraintlayout.core.motion.utils.TypedValues;
@@ -42,6 +41,8 @@
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 import androidx.constraintlayout.core.widgets.Flow;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/State.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/State.java
index a0f208d..84056ff 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/State.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/State.java
@@ -20,7 +20,6 @@
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.CHAIN_SPREAD;
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.CHAIN_SPREAD_INSIDE;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.core.state.helpers.AlignHorizontallyReference;
 import androidx.constraintlayout.core.state.helpers.AlignVerticallyReference;
 import androidx.constraintlayout.core.state.helpers.BarrierReference;
@@ -33,6 +32,8 @@
 import androidx.constraintlayout.core.widgets.ConstraintWidgetContainer;
 import androidx.constraintlayout.core.widgets.HelperWidget;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -423,8 +424,7 @@
      * @param gridType type of Grid pattern - Grid, Row, or Column
      * @return a GridReference object
      */
-    @NonNull
-    public GridReference getGrid(@NonNull Object key, @NonNull String gridType) {
+    public @NonNull GridReference getGrid(@NonNull Object key, @NonNull String gridType) {
         ConstraintReference reference = constraints(key);
         if (reference.getFacade() == null || !(reference.getFacade() instanceof GridReference)) {
             State.Helper Type = Helper.GRID;
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/Transition.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/Transition.java
index cf66b93..9b605dd 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/Transition.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/Transition.java
@@ -16,7 +16,6 @@
 
 package androidx.constraintlayout.core.state;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.constraintlayout.core.motion.CustomVariable;
 import androidx.constraintlayout.core.motion.Motion;
@@ -35,6 +34,8 @@
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 import androidx.constraintlayout.core.widgets.ConstraintWidgetContainer;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/TransitionParser.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/TransitionParser.java
index 9801b39..29b7c16 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/TransitionParser.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/TransitionParser.java
@@ -18,7 +18,6 @@
 
 import static androidx.constraintlayout.core.state.ConstraintSetParser.parseColorString;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.constraintlayout.core.motion.CustomVariable;
 import androidx.constraintlayout.core.motion.utils.TypedBundle;
@@ -31,6 +30,8 @@
 import androidx.constraintlayout.core.parser.CLObject;
 import androidx.constraintlayout.core.parser.CLParsingException;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * Contains code for Parsing Transitions
  */
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/WidgetFrame.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/WidgetFrame.java
index 4adf478..5ab1701 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/WidgetFrame.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/WidgetFrame.java
@@ -16,7 +16,6 @@
 
 package androidx.constraintlayout.core.state;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.core.motion.CustomAttribute;
 import androidx.constraintlayout.core.motion.CustomVariable;
 import androidx.constraintlayout.core.motion.utils.TypedBundle;
@@ -29,6 +28,8 @@
 import androidx.constraintlayout.core.widgets.ConstraintAnchor;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.HashMap;
 import java.util.Set;
 
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/ChainReference.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/ChainReference.java
index 51269c7..ea5b4a7 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/ChainReference.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/ChainReference.java
@@ -18,11 +18,12 @@
 
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.UNKNOWN;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.constraintlayout.core.state.HelperReference;
 import androidx.constraintlayout.core.state.State;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.HashMap;
 
 /**
@@ -55,13 +56,13 @@
     private HashMap<String, Float> mMapPreGoneMargin;
     private HashMap<String, Float> mMapPostGoneMargin;
 
-    protected @NonNull State.Chain mStyle = State.Chain.SPREAD;
+    protected State.@NonNull Chain mStyle = State.Chain.SPREAD;
 
-    public ChainReference(@NonNull State state, @NonNull State.Helper type) {
+    public ChainReference(@NonNull State state, State.@NonNull Helper type) {
         super(state, type);
     }
 
-    public @NonNull State.Chain getStyle() {
+    public State.@NonNull Chain getStyle() {
         return State.Chain.SPREAD;
     }
 
@@ -71,8 +72,7 @@
      * @param style Defines the way the chain will lay out its elements
      * @return This same instance
      */
-    @NonNull
-    public ChainReference style(@NonNull State.Chain style) {
+    public @NonNull ChainReference style(State.@NonNull Chain style) {
         mStyle = style;
         return this;
     }
@@ -191,9 +191,8 @@
     }
 
     // @TODO: add description
-    @NonNull
     @Override
-    public ChainReference bias(float bias) {
+    public @NonNull ChainReference bias(float bias) {
         mBias = bias;
         return this;
     }
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/GridReference.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/GridReference.java
index d2168ad..900ef31 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/GridReference.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/state/helpers/GridReference.java
@@ -16,13 +16,14 @@
 
 package androidx.constraintlayout.core.state.helpers;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.constraintlayout.core.state.HelperReference;
 import androidx.constraintlayout.core.state.State;
 import androidx.constraintlayout.core.utils.GridCore;
 import androidx.constraintlayout.core.widgets.HelperWidget;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 /**
  * A HelperReference of a Grid Helper that helps enable Grid in Compose
  */
@@ -31,7 +32,7 @@
     private static final String SPANS_RESPECT_WIDGET_ORDER_STRING = "spansrespectwidgetorder";
     private static final String SUB_GRID_BY_COL_ROW_STRING = "subgridbycolrow";
 
-    public GridReference(@NonNull State state, @NonNull State.Helper type) {
+    public GridReference(@NonNull State state, State.@NonNull Helper type) {
         super(state, type);
         if (type == State.Helper.ROW) {
             this.mRowsSet = 1;
@@ -292,8 +293,7 @@
      * Get the row weights
      * @return the row weights
      */
-    @Nullable
-    public String getRowWeights() {
+    public @Nullable String getRowWeights() {
         return mRowWeights;
     }
 
@@ -309,8 +309,7 @@
      * Get the column weights
      * @return the column weights
      */
-    @Nullable
-    public String getColumnWeights() {
+    public @Nullable String getColumnWeights() {
         return mColumnWeights;
     }
 
@@ -326,8 +325,7 @@
      * Get the spans
      * @return the spans
      */
-    @Nullable
-    public String getSpans() {
+    public @Nullable String getSpans() {
         return mSpans;
     }
 
@@ -343,8 +341,7 @@
      * Get the skips
      * @return the skips
      */
-    @Nullable
-    public String getSkips() {
+    public @Nullable String getSkips() {
         return mSkips;
     }
 
@@ -361,8 +358,7 @@
      * @return the helper widget (Grid)
      */
     @Override
-    @NonNull
-    public HelperWidget getHelperWidget() {
+    public @NonNull HelperWidget getHelperWidget() {
         if (mGrid == null) {
             mGrid = new GridCore();
         }
diff --git a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/utils/GridCore.java b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/utils/GridCore.java
index 7424e64c..6d72d91 100644
--- a/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/utils/GridCore.java
+++ b/constraintlayout/constraintlayout-core/src/main/java/androidx/constraintlayout/core/utils/GridCore.java
@@ -18,13 +18,14 @@
 
 import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.MATCH_CONSTRAINT;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.constraintlayout.core.LinearSystem;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 import androidx.constraintlayout.core.widgets.ConstraintWidgetContainer;
 import androidx.constraintlayout.core.widgets.VirtualLayout;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
@@ -181,8 +182,7 @@
      *
      * @return the parent ConstraintWidgetContainer
      */
-    @Nullable
-    public ConstraintWidgetContainer getContainer() {
+    public @Nullable ConstraintWidgetContainer getContainer() {
         return mContainer;
     }
 
@@ -278,8 +278,7 @@
      *
      * @return the string value of rowWeights
      */
-    @Nullable
-    public String getRowWeights() {
+    public @Nullable String getRowWeights() {
         return mRowWeights;
     }
 
@@ -301,8 +300,7 @@
      *
      * @return the string value of columnWeights
      */
-    @Nullable
-    public String getColumnWeights() {
+    public @Nullable String getColumnWeights() {
         return mColumnWeights;
     }
 
diff --git a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/AdvancedChainTest.java b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/AdvancedChainTest.java
index 2064aa3..cfdb016 100644
--- a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/AdvancedChainTest.java
+++ b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/AdvancedChainTest.java
@@ -28,7 +28,6 @@
 
 import java.util.ArrayList;
 
-
 public class AdvancedChainTest {
 
     @Test
diff --git a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/ArrayLinkedVariablesTest.java b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/ArrayLinkedVariablesTest.java
index 991f996..adac6db 100644
--- a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/ArrayLinkedVariablesTest.java
+++ b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/ArrayLinkedVariablesTest.java
@@ -20,7 +20,6 @@
 
 import org.junit.Test;
 
-
 /**
  * Test nested layout
  */
diff --git a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/BarrierTest.java b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/BarrierTest.java
index 64fd187..faa0e2c 100644
--- a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/BarrierTest.java
+++ b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/BarrierTest.java
@@ -27,7 +27,6 @@
 
 import org.junit.Test;
 
-
 /**
  * Tests for Barriers
  */
diff --git a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/RandomLayoutTest.java b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/RandomLayoutTest.java
index de79560..c823105 100644
--- a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/RandomLayoutTest.java
+++ b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/RandomLayoutTest.java
@@ -28,7 +28,6 @@
 import java.util.ArrayList;
 import java.util.Random;
 
-
 /**
  * This test creates a random set of non overlapping rectangles uses the scout
  * to add a sequence of constraints. Verify that the constraint engine will then layout the
diff --git a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/widgets/ChainHeadTest.java b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/widgets/ChainHeadTest.java
index 1c85799..bd9d2d1 100644
--- a/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/widgets/ChainHeadTest.java
+++ b/constraintlayout/constraintlayout-core/src/test/java/androidx/constraintlayout/core/widgets/ChainHeadTest.java
@@ -24,7 +24,6 @@
 
 import org.junit.Test;
 
-
 public class ChainHeadTest {
 
     @Test
diff --git a/constraintlayout/constraintlayout/build.gradle b/constraintlayout/constraintlayout/build.gradle
index c29662e..cf91f8b 100644
--- a/constraintlayout/constraintlayout/build.gradle
+++ b/constraintlayout/constraintlayout/build.gradle
@@ -29,6 +29,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     implementation("androidx.appcompat:appcompat:1.2.0")
     implementation("androidx.core:core:1.3.2")
     implementation(project(":constraintlayout:constraintlayout-core"))
@@ -48,6 +49,4 @@
     mavenVersion = LibraryVersions.CONSTRAINTLAYOUT
     inceptionYear = "2022"
     description = "This library offers a flexible and adaptable way to position and animate widgets"
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Grid.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Grid.java
index 5d23e12..d99fd40 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Grid.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Grid.java
@@ -24,12 +24,13 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
 import androidx.constraintlayout.widget.R;
 import androidx.constraintlayout.widget.VirtualLayout;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
index ef888ce..bf3d856 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java
@@ -49,8 +49,6 @@
 import android.widget.TextView;
 
 import androidx.annotation.IdRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.constraintlayout.core.motion.utils.KeyCache;
 import androidx.constraintlayout.core.widgets.ConstraintAnchor;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
@@ -68,13 +66,15 @@
 import androidx.constraintlayout.widget.R;
 import androidx.core.view.NestedScrollingParent3;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-
 /**
  * A subclass of ConstraintLayout that supports animating between
  * various states <b>Added in 2.0</b>
@@ -3161,7 +3161,7 @@
     public void onNestedPreScroll(@NonNull View target,
                                   int dx,
                                   int dy,
-                                  @NonNull int[] consumed,
+                                  int @NonNull [] consumed,
                                   int type) {
 
         MotionScene scene = mScene;
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionPaths.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionPaths.java
index b695b5b..2baf01c 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionPaths.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionPaths.java
@@ -21,11 +21,12 @@
 import android.util.Log;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.core.motion.utils.Easing;
 import androidx.constraintlayout.widget.ConstraintAttribute;
 import androidx.constraintlayout.widget.ConstraintSet;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.Set;
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java
index a755550..db9c224 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java
@@ -29,11 +29,12 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.constraintlayout.widget.R;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * An AppCompatImageButton that can display, combine and filter images. <b>Added in 2.0</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java
index 4ca975c..8890b9a 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java
@@ -32,11 +32,12 @@
 import android.view.ViewOutlineProvider;
 import android.widget.ImageView;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.constraintlayout.widget.R;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * An ImageView that can display, combine and filter images. <b>Added in 2.0</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MockView.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MockView.java
index 389bfa7..d850868 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MockView.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MockView.java
@@ -26,9 +26,10 @@
 import android.util.DisplayMetrics;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.widget.R;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * A view that is useful for prototyping layouts. <b>Added in 2.0</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java
index 93d791c..4e7c7ba 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java
@@ -27,10 +27,11 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.constraintlayout.widget.R;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * A MotionButton is an AppCompatButton that can round its edges. <b>Added in 2.0</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java
index 9d1a216..0b5765d 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java
@@ -42,14 +42,15 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.constraintlayout.motion.widget.Debug;
 import androidx.constraintlayout.motion.widget.FloatLayout;
 import androidx.constraintlayout.widget.R;
 import androidx.core.widget.TextViewCompat;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.Objects;
 
 /**
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionTelltales.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionTelltales.java
index 38a2433..068fb17 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionTelltales.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/utils/widget/MotionTelltales.java
@@ -24,10 +24,11 @@
 import android.util.AttributeSet;
 import android.view.ViewParent;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.motion.widget.MotionLayout;
 import androidx.constraintlayout.widget.R;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * A view that is useful for prototyping Views that will move in MotionLayout. <b>Added in 2.0</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintHelper.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintHelper.java
index 7b1e135..c0aadaa 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintHelper.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintHelper.java
@@ -27,12 +27,13 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 import androidx.constraintlayout.core.widgets.ConstraintWidgetContainer;
 import androidx.constraintlayout.core.widgets.Helper;
 import androidx.constraintlayout.core.widgets.HelperWidget;
 
+import org.jspecify.annotations.NonNull;
+
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.HashMap;
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
index 94ccc7b..163d4f5 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
@@ -41,8 +41,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.constraintlayout.core.LinearSystem;
 import androidx.constraintlayout.core.Metrics;
 import androidx.constraintlayout.core.widgets.ConstraintAnchor;
@@ -52,6 +50,9 @@
 import androidx.constraintlayout.core.widgets.Optimizer;
 import androidx.constraintlayout.core.widgets.analyzer.BasicMeasure;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java
index a161340..c708831 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java
@@ -22,7 +22,6 @@
 import androidx.constraintlayout.core.Metrics;
 
 import java.text.DecimalFormat;
-import java.util.ArrayList;
 
 /**
  * This provide metrics of the complexity of the layout that is being solved.
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Guideline.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Guideline.java
index 577a8d7..8e41650 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Guideline.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Guideline.java
@@ -22,7 +22,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * Utility class representing a Guideline helper object for
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Placeholder.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Placeholder.java
index dd60e03..0ee1008 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Placeholder.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/Placeholder.java
@@ -26,9 +26,10 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.core.widgets.ConstraintWidget;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * <b>Added in 1.1</b>
  * <p>
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ReactiveGuide.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ReactiveGuide.java
index 9f7bde2..fec9008 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ReactiveGuide.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ReactiveGuide.java
@@ -23,9 +23,10 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.NonNull;
 import androidx.constraintlayout.motion.widget.MotionLayout;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * Utility class representing a reactive Guideline helper object for {@link ConstraintLayout}.
  */
diff --git a/contentpager/contentpager/build.gradle b/contentpager/contentpager/build.gradle
index 4d04d51..b9a4313 100644
--- a/contentpager/contentpager/build.gradle
+++ b/contentpager/contentpager/build.gradle
@@ -29,6 +29,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api("androidx.annotation:annotation:1.8.1")
     api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.4.2")
@@ -47,8 +48,6 @@
     inceptionYear = "2017"
     description = "Library providing support for paging across content exposed via a ContentProvider. Use of this library allows a client to avoid expensive interprocess \"cursor window swaps\" on the UI thread."
     failOnDeprecationWarnings = false
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
 
 android {
diff --git a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/ContentPagerTest.java b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/ContentPagerTest.java
index 7b5f3c7..950e8eb 100644
--- a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/ContentPagerTest.java
+++ b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/ContentPagerTest.java
@@ -33,11 +33,11 @@
 import android.os.Handler;
 import android.os.Looper;
 
-import androidx.annotation.Nullable;
 import androidx.contentpager.content.ContentPager.ContentCallback;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import org.jspecify.annotations.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/LoaderQueryRunnerTest.java b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/LoaderQueryRunnerTest.java
index a6eaaa8..6f4f4e0 100644
--- a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/LoaderQueryRunnerTest.java
+++ b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/LoaderQueryRunnerTest.java
@@ -22,12 +22,12 @@
 import android.app.Activity;
 import android.database.Cursor;
 
-import androidx.annotation.NonNull;
 import androidx.contentpager.content.ContentPager.ContentCallback;
 import androidx.contentpager.content.ContentPager.QueryRunner;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 
+import org.jspecify.annotations.NonNull;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestContentProvider.java b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestContentProvider.java
index 885bd1e..88eeed4 100644
--- a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestContentProvider.java
+++ b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestContentProvider.java
@@ -30,9 +30,10 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.jspecify.annotations.Nullable;
+
 /**
  * A stub data paging provider used for testing of paging support.
  * Ignores client supplied projections.
@@ -89,7 +90,7 @@
 
     @Override
     public Cursor query(
-            Uri uri, @Nullable String[] projection, String selection, String[] selectionArgs,
+            Uri uri, String @Nullable [] projection, String selection, String[] selectionArgs,
             String sortOrder) {
         return query(uri, projection, null, null);
     }
@@ -134,7 +135,7 @@
             return value;
         }
 
-        @Nullable String argValue = uri.getQueryParameter(key);
+        String argValue = uri.getQueryParameter(key);
         if (argValue != null) {
             try {
                 return Integer.parseInt(argValue);
diff --git a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestQueryCallback.java b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestQueryCallback.java
index 320d463..737ae17 100644
--- a/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestQueryCallback.java
+++ b/contentpager/contentpager/src/androidTest/java/androidx/contentpager/content/TestQueryCallback.java
@@ -25,9 +25,10 @@
 import android.net.Uri;
 import android.os.Bundle;
 
-import androidx.annotation.Nullable;
 import androidx.core.util.Pair;
 
+import org.jspecify.annotations.Nullable;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
diff --git a/contentpager/contentpager/src/main/java/androidx/contentpager/content/ContentPager.java b/contentpager/contentpager/src/main/java/androidx/contentpager/content/ContentPager.java
index 2882853..2f5fbac 100644
--- a/contentpager/contentpager/src/main/java/androidx/contentpager/content/ContentPager.java
+++ b/contentpager/contentpager/src/main/java/androidx/contentpager/content/ContentPager.java
@@ -34,13 +34,14 @@
 import androidx.annotation.GuardedBy;
 import androidx.annotation.IntDef;
 import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresPermission;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 import androidx.collection.LruCache;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.HashSet;
@@ -279,8 +280,8 @@
      */
     @MainThread
     public @NonNull Query query(
-            @NonNull @RequiresPermission.Read Uri uri,
-            @Nullable String[] projection,
+            @RequiresPermission.Read @NonNull Uri uri,
+            String @Nullable [] projection,
             @NonNull Bundle queryArgs,
             @Nullable CancellationSignal cancellationSignal,
             @NonNull ContentCallback callback) {
diff --git a/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner.java b/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner.java
index 7054cfe..dbcbb05 100644
--- a/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner.java
+++ b/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner.java
@@ -25,7 +25,7 @@
 import android.os.Bundle;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * A {@link ContentPager.QueryRunner} that executes queries using a {@link LoaderManager}.
@@ -48,7 +48,7 @@
 
     @Override
     @SuppressWarnings({"unchecked", "deprecation"})
-    public void query(final @NonNull Query query, @NonNull final Callback callback) {
+    public void query(final @NonNull Query query, final @NonNull Callback callback) {
         if (DEBUG) Log.d(TAG, "Handling query: " + query);
 
         android.app.LoaderManager.LoaderCallbacks<Cursor> callbacks =
diff --git a/contentpager/contentpager/src/main/java/androidx/contentpager/content/Query.java b/contentpager/contentpager/src/main/java/androidx/contentpager/content/Query.java
index a48c380..4c6d9fb 100644
--- a/contentpager/contentpager/src/main/java/androidx/contentpager/content/Query.java
+++ b/contentpager/contentpager/src/main/java/androidx/contentpager/content/Query.java
@@ -26,8 +26,8 @@
 import android.os.CancellationSignal;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 import java.util.Arrays;
 
@@ -41,7 +41,7 @@
     private static final String TAG = "Query";
 
     private final Uri mUri;
-    private final @Nullable String[] mProjection;
+    private final String @Nullable [] mProjection;
     private final Bundle mQueryArgs;
 
     private final int mId;
@@ -53,10 +53,10 @@
 
     Query(
             @NonNull Uri uri,
-            @Nullable String[] projection,
+            String @Nullable [] projection,
             @NonNull Bundle args,
             @Nullable CancellationSignal cancellationSignal,
-            @NonNull ContentPager.ContentCallback callback) {
+            ContentPager.@NonNull ContentCallback callback) {
 
         checkArgument(uri != null);
         checkArgument(args != null);
@@ -107,7 +107,7 @@
         return mLimit;
     }
 
-    @NonNull ContentPager.ContentCallback getCallback() {
+    ContentPager.@NonNull ContentCallback getCallback() {
         return mCallback;
     }
 
diff --git a/core/core-ktx/api/api_lint.ignore b/core/core-ktx/api/api_lint.ignore
index 3cac25a..2373a95 100644
--- a/core/core-ktx/api/api_lint.ignore
+++ b/core/core-ktx/api/api_lint.ignore
@@ -1,8 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.core.database.sqlite.SQLiteDatabaseKt:
-    Acronyms should not be capitalized in class names: was `SQLiteDatabaseKt`, should this be `SqLiteDatabaseKt`?
-
-
 AutoBoxing: androidx.core.database.CursorKt#getDoubleOrNull(android.database.Cursor, int):
     Must avoid boxed primitives (`java.lang.Double`)
 AutoBoxing: androidx.core.database.CursorKt#getFloatOrNull(android.database.Cursor, int):
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/PreCallEndpointsTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/PreCallEndpointsTest.kt
index f1bcaff..196e174 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/PreCallEndpointsTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/PreCallEndpointsTest.kt
@@ -112,4 +112,27 @@
         val res = currentPreCallEndpoints.maybeRemoveCallEndpoint(defaultSpeaker)
         assertEquals(PreCallEndpointsUpdater.STOP_TRACKING_REMOVED_ENDPOINT, res)
     }
+
+    /**
+     * This test verifies that the updateClient() function returns an immutable list. It checks that
+     * attempting to modify the returned list (using reversed()) does not alter its contents.
+     */
+    @SmallTest
+    @Test
+    fun testPreCallEndpointUpdaterEmitsImmutableList() {
+        // Given: a PreCallEndpointsUpdater
+        val sendChannel = Channel<List<CallEndpointCompat>>(Channel.BUFFERED)
+        val currentPreCallEndpoints =
+            PreCallEndpointsUpdater(mutableListOf(defaultEarpiece, defaultSpeaker), sendChannel)
+        // When: an update is emitted to the client
+        val finalList = currentPreCallEndpoints.updateClient()
+        assertEquals(defaultSpeaker, finalList[0])
+        assertEquals(defaultEarpiece, finalList[1])
+        // Then: verify the list is immutable
+        finalList.reversed()
+        assertEquals(defaultSpeaker, finalList[0])
+        assertEquals(defaultEarpiece, finalList[1])
+        // cleanup
+        sendChannel.close()
+    }
 }
diff --git a/core/core-telecom/src/main/java/androidx/core/telecom/internal/PreCallEndpointsUpdater.kt b/core/core-telecom/src/main/java/androidx/core/telecom/internal/PreCallEndpointsUpdater.kt
index 837d51c..b949f00 100644
--- a/core/core-telecom/src/main/java/androidx/core/telecom/internal/PreCallEndpointsUpdater.kt
+++ b/core/core-telecom/src/main/java/androidx/core/telecom/internal/PreCallEndpointsUpdater.kt
@@ -128,9 +128,7 @@
         }
     }
 
-    private fun updateClient() {
-        // Sort by endpoint type.  The first element has the highest priority!
-        mCurrentDevices.sort()
-        mSendChannel.trySend(mCurrentDevices)
+    internal fun updateClient(): List<CallEndpointCompat> {
+        return mCurrentDevices.sorted().also { mSendChannel.trySend(it) }
     }
 }
diff --git a/core/core/api/api_lint.ignore b/core/core/api/api_lint.ignore
index c28cad6..966f30a 100644
--- a/core/core/api/api_lint.ignore
+++ b/core/core/api/api_lint.ignore
@@ -1,6 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.core.database.sqlite.SQLiteCursorCompat:
-    Acronyms should not be capitalized in class names: was `SQLiteCursorCompat`, should this be `SqLiteCursorCompat`?
 AcronymName: androidx.core.graphics.ColorUtils#blendARGB(int, int, float):
     Acronyms should not be capitalized in method names: was `blendARGB`, should this be `blendArgb`?
 AcronymName: androidx.core.graphics.ColorUtils#blendHSL(float[], float[], float, float[]):
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 45edc44..d8f9bf5 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -1870,6 +1870,7 @@
   }
 
   public final class BuildCompat {
+    method @ChecksSdkIntAtLeast(api=36, codename="Baklava") public static boolean isAtLeastB();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 46e97fe..dc7f4a4eb 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -2263,6 +2263,7 @@
   }
 
   public final class BuildCompat {
+    method @ChecksSdkIntAtLeast(api=36, codename="Baklava") public static boolean isAtLeastB();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
diff --git a/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java b/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
index 26087bd..e9764cd 100644
--- a/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
@@ -51,6 +51,13 @@
         assertFalse(BuildCompat.isAtLeastPreReleaseCodename("S", "REL"));
 
         assertFalse(BuildCompat.isAtLeastPreReleaseCodename("RMR1", "REL"));
+
+        assertFalse(BuildCompat.isAtLeastPreReleaseCodename("RMR1", "REL"));
+
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("VanillaIceCream", "VanillaIceCream"));
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("VanillaIceCream", "Baklava"));
+        assertTrue(BuildCompat.isAtLeastPreReleaseCodename("Baklava", "Baklava"));
+        assertFalse(BuildCompat.isAtLeastPreReleaseCodename("Baklava", "VanillaIceCream"));
     }
 
     @Test
@@ -82,4 +89,10 @@
     public void isAtLeastV_byMinSdk() {
         assertTrue(BuildCompat.isAtLeastV());
     }
+
+    @SdkSuppress(minSdkVersion = 36)
+    @Test
+    public void isAtLeastB_byMinSdk() {
+        assertTrue(BuildCompat.isAtLeastB());
+    }
 }
diff --git a/core/core/src/main/java/androidx/core/os/BuildCompat.kt b/core/core/src/main/java/androidx/core/os/BuildCompat.kt
index 22937a3..0cfe5a7 100644
--- a/core/core/src/main/java/androidx/core/os/BuildCompat.kt
+++ b/core/core/src/main/java/androidx/core/os/BuildCompat.kt
@@ -40,13 +40,32 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @VisibleForTesting
     public fun isAtLeastPreReleaseCodename(codename: String, buildCodename: String): Boolean {
+        fun codenameToInt(codename: String): Int? =
+            when (codename.uppercase()) {
+                "BAKLAVA" -> 0
+                else -> null
+            }
+
         // Special case "REL", which means the build is not a pre-release build.
         if ("REL" == buildCodename) {
             return false
         }
-        // Otherwise lexically compare them.  Return true if the build codename is equal to or
-        // greater than the requested codename.
-        return buildCodename.uppercase() >= codename.uppercase()
+
+        // Starting with Baklava, the Android dessert names wrapped around to the start of the
+        // alphabet; handle these "new" codenames explicitly; lexically compare "old" codenames.
+        // Return true if the build codename is equal to or greater than the requested codename.
+        val buildCodenameInt = codenameToInt(buildCodename)
+        val codenameInt = codenameToInt(codename)
+        if (buildCodenameInt != null && codenameInt != null) {
+            // both codenames are "new" -> use hard-coded int values
+            return buildCodenameInt >= codenameInt
+        } else if (buildCodenameInt == null && codenameInt == null) {
+            // both codenames are "old" -> use lexical comparison
+            return buildCodename.uppercase() >= codename.uppercase()
+        } else {
+            // one codename is "new", one is "old"
+            return buildCodenameInt != null
+        }
     }
 
     /**
@@ -271,6 +290,22 @@
                 isAtLeastPreReleaseCodename("VanillaIceCream", Build.VERSION.CODENAME))
 
     /**
+     * Checks if the device is running on a pre-release version of Android Baklava or a release
+     * version of Android Baklava or newer.
+     *
+     * **Note:** When Android Baklava is finalized for release, this method will be removed and all
+     * calls must be replaced with `Build.VERSION.SDK_INT >= 36`.
+     *
+     * @return `true` if Baklava APIs are available for use, `false` otherwise
+     */
+    @JvmStatic
+    @ChecksSdkIntAtLeast(api = 36, codename = "Baklava")
+    public fun isAtLeastB(): Boolean =
+        Build.VERSION.SDK_INT >= 36 ||
+            (Build.VERSION.SDK_INT >= 35 &&
+                isAtLeastPreReleaseCodename("Baklava", Build.VERSION.CODENAME))
+
+    /**
      * Experimental feature set for pre-release SDK checks.
      *
      * Pre-release SDK checks **do not** guarantee correctness, as APIs may have been added or
diff --git a/credentials/credentials-e2ee/build.gradle b/credentials/credentials-e2ee/build.gradle
index 002d73b..b36889d 100644
--- a/credentials/credentials-e2ee/build.gradle
+++ b/credentials/credentials-e2ee/build.gradle
@@ -23,6 +23,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api(libs.kotlinStdlib)
     api("androidx.annotation:annotation:1.8.1")
     implementation("com.google.crypto.tink:tink-android:1.8.0")
@@ -44,6 +45,4 @@
     description = "Create Identity Keys, signing keys for E2EE in AOSP."
     mavenVersion = LibraryVersions.CREDENTIALS_E2EE_QUARANTINE
     legacyDisableKotlinStrictApiMode = true
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/credentials/credentials-e2ee/src/androidTest/java/androidx/credentials/e2ee/IdentityKeyJavaTest.java b/credentials/credentials-e2ee/src/androidTest/java/androidx/credentials/e2ee/IdentityKeyJavaTest.java
index 61795cb..cece85a 100644
--- a/credentials/credentials-e2ee/src/androidTest/java/androidx/credentials/e2ee/IdentityKeyJavaTest.java
+++ b/credentials/credentials-e2ee/src/androidTest/java/androidx/credentials/e2ee/IdentityKeyJavaTest.java
@@ -20,10 +20,9 @@
 
 import android.util.Base64;
 
-import androidx.annotation.NonNull;
-
 import com.google.common.io.BaseEncoding;
 
+import org.jspecify.annotations.NonNull;
 import org.junit.Test;
 
 import java.util.Random;
@@ -32,8 +31,7 @@
 public class IdentityKeyJavaTest {
     Random mRandom = new Random();
 
-    @NonNull
-    private byte[] randBytes(int numBytes) {
+    private byte @NonNull [] randBytes(int numBytes) {
         byte[] bytes = new byte[numBytes];
         mRandom.nextBytes(bytes);
         return bytes;
diff --git a/credentials/credentials/build.gradle b/credentials/credentials/build.gradle
index a405ea3..450d9da 100644
--- a/credentials/credentials/build.gradle
+++ b/credentials/credentials/build.gradle
@@ -30,6 +30,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api("androidx.annotation:annotation:1.8.1")
     api("androidx.biometric:biometric:1.1.0")
     api(libs.kotlinStdlib)
@@ -65,6 +66,4 @@
     description = "Android Credentials Library"
     legacyDisableKotlinStrictApiMode = true
     samples(project(":credentials:credentials-samples"))
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
index b9a7f1b..36472cb 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialManagerJavaTest.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.os.Looper;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.credentials.exceptions.ClearCredentialException;
 import androidx.credentials.exceptions.ClearCredentialProviderConfigurationException;
@@ -39,6 +38,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.jspecify.annotations.NonNull;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
index 30a90a7..979a543 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/CredentialProviderFactoryTest.kt
@@ -17,6 +17,7 @@
 
 import android.os.Build
 import androidx.credentials.ClearCredentialStateRequest.Companion.TYPE_CLEAR_RESTORE_CREDENTIAL
+import androidx.credentials.internal.FormFactorHelper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
@@ -239,4 +240,36 @@
         assertThat(credentialProviderFactory.getBestAvailableProvider(request))
             .isEqualTo(expectedProvider)
     }
+
+    @Test
+    fun getBestAvailableProvider_onTV_preUSuccess() {
+        if (!FormFactorHelper.isTV(context)) {
+            return
+        }
+        clearState()
+        val expectedPreUProvider = FakeProvider(success = true)
+        credentialProviderFactory.testMode = true
+        credentialProviderFactory.testPreUProvider = expectedPreUProvider
+
+        val actualProvider = credentialProviderFactory.getBestAvailableProvider()
+
+        assertThat(actualProvider).isNotNull()
+        assertThat(actualProvider).isEqualTo(expectedPreUProvider)
+    }
+
+    @Test
+    fun getBestAvailableProvider_onAuto_preUSuccess() {
+        if (!FormFactorHelper.isAuto(context)) {
+            return
+        }
+        clearState()
+        val expectedPreUProvider = FakeProvider(success = true)
+        credentialProviderFactory.testMode = true
+        credentialProviderFactory.testPreUProvider = expectedPreUProvider
+
+        val actualProvider = credentialProviderFactory.getBestAvailableProvider()
+
+        assertThat(actualProvider).isNotNull()
+        assertThat(actualProvider).isEqualTo(expectedPreUProvider)
+    }
 }
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/GetPublicKeyCredentialOptionJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/GetPublicKeyCredentialOptionJavaTest.java
index 7369666..90a03f8 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/GetPublicKeyCredentialOptionJavaTest.java
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/GetPublicKeyCredentialOptionJavaTest.java
@@ -37,7 +37,6 @@
 
 import java.util.Set;
 
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class GetPublicKeyCredentialOptionJavaTest {
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/GetRestoreCredentialOptionJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/GetRestoreCredentialOptionJavaTest.java
index 9b6d76f..c595e38 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/GetRestoreCredentialOptionJavaTest.java
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/GetRestoreCredentialOptionJavaTest.java
@@ -26,7 +26,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class GetRestoreCredentialOptionJavaTest {
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/provider/PendingIntentHandlerApi23JavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/provider/PendingIntentHandlerApi23JavaTest.java
index 68ec0e6..fd558ba 100644
--- a/credentials/credentials/src/androidTest/java/androidx/credentials/provider/PendingIntentHandlerApi23JavaTest.java
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/provider/PendingIntentHandlerApi23JavaTest.java
@@ -38,7 +38,6 @@
 import android.os.Build;
 import android.os.Bundle;
 
-import androidx.annotation.Nullable;
 import androidx.credentials.CreateCredentialRequest;
 import androidx.credentials.CreateCredentialResponse;
 import androidx.credentials.CreateCustomCredentialResponse;
@@ -64,6 +63,7 @@
 import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
+import org.jspecify.annotations.Nullable;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
index 0155a98..9d811357 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
@@ -24,6 +24,7 @@
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
 import androidx.credentials.ClearCredentialStateRequest.Companion.TYPE_CLEAR_RESTORE_CREDENTIAL
+import androidx.credentials.internal.FormFactorHelper
 
 /** Factory that returns the credential provider to be used by Credential Manager. */
 @OptIn(ExperimentalDigitalCredentialApi::class)
@@ -94,6 +95,10 @@
      * library. Post-U, providers will be registered with the framework, and enabled by the user.
      */
     fun getBestAvailableProvider(shouldFallbackToPreU: Boolean = true): CredentialProvider? {
+        if (FormFactorHelper.isTV(context) || FormFactorHelper.isAuto(context)) {
+            return tryCreateClosedSourceProviderFromManifest()
+        }
+
         if (Build.VERSION.SDK_INT >= 34) { // Android U
             val postUProvider = tryCreatePostUProvider()
             if (postUProvider == null && shouldFallbackToPreU) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt b/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt
new file mode 100644
index 0000000..e669f38
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/internal/FormFactorHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.credentials.internal
+
+import android.content.Context
+import android.content.pm.PackageManager
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+object FormFactorHelper {
+    /** Determines whether the device is a TV. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isTV(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+    }
+
+    /** Determines whether the device is a Wearable. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isWear(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+    }
+
+    /** Determines whether the device is a Auto. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @JvmStatic
+    fun isAuto(ctx: Context): Boolean {
+        val pm = ctx.packageManager
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    }
+}
diff --git a/credentials/registry/registry-provider/build.gradle b/credentials/registry/registry-provider/build.gradle
index 2cb6006..7ab03bca 100644
--- a/credentials/registry/registry-provider/build.gradle
+++ b/credentials/registry/registry-provider/build.gradle
@@ -30,6 +30,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api(libs.kotlinStdlib)
     api(project(":credentials:credentials"))
     implementation(libs.kotlinCoroutinesCore)
@@ -54,6 +55,4 @@
     type = LibraryType.PUBLISHED_LIBRARY
     inceptionYear = "2024"
     description = "register digital credentials with CredentialManager to support smooth sign-in, verification, and other user experience"
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/credentials/registry/registry-provider/src/androidTest/java/androidx/credentials/registry/provider/RegistryManagerJavaTest.java b/credentials/registry/registry-provider/src/androidTest/java/androidx/credentials/registry/provider/RegistryManagerJavaTest.java
index bbb97db..621e17c 100644
--- a/credentials/registry/registry-provider/src/androidTest/java/androidx/credentials/registry/provider/RegistryManagerJavaTest.java
+++ b/credentials/registry/registry-provider/src/androidTest/java/androidx/credentials/registry/provider/RegistryManagerJavaTest.java
@@ -20,12 +20,12 @@
 
 import android.content.Context;
 
-import androidx.annotation.NonNull;
 import androidx.credentials.CredentialManagerCallback;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.jspecify.annotations.NonNull;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/development/requirerelnote.py b/development/requirerelnote.py
new file mode 100755
index 0000000..2f734d3
--- /dev/null
+++ b/development/requirerelnote.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+
+#
+# Copyright 2025, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     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.
+#
+
+"""Script that enforces Relnote: any file path in the commit contains module substring"""
+
+import argparse
+import os.path
+import re
+import sys
+
+ERROR_RELNOTE_REQUIRED = """
+RELNOTE: is required for commits that contain changes in {}
+
+Please add a RELNOTE to the commit or RELNOTE: N/A if a release note is not applicable to the
+commit.
+
+A RELNOTE is required for all commits that changes the release artifacts.
+
+A RELNOTE can be N/A for commit messages that only effects tooling, documentation, directory
+structure, etc., but not the release artifacts.
+"""
+
+def main(args=None):
+    parser = argparse.ArgumentParser(
+        prog="requirerelnote",
+        description="Check if RELNOTE is required")
+    parser.add_argument('--file', nargs='+')
+    parser.add_argument('--module')
+    parser.add_argument('--commit')
+
+    args = parser.parse_args()
+
+    source_files = [f for f in args.file
+               if (not "buildSrc/" in f and
+                  "/src/main/" in f or
+                  "/src/commonMain/" in f or
+                  "/src/androidMain/" in f)]
+    module_files = [f for f in source_files
+                if (args.module in f)]
+
+    if not module_files:
+        sys.exit(0)
+
+    """Following copied (with minor edits) from hooks.py:check_commit_msg_relnote_for_current_txt"""
+    """Check if the commit contain the 'Relnote:' stanza."""
+    field = 'Relnote'
+    regex = fr'^{field}: .+$'
+    check_re = re.compile(regex, re.IGNORECASE)
+
+    found = []
+    for line in args.commit.splitlines():
+        if check_re.match(line):
+            found.append(line)
+
+    if not found:
+        print(ERROR_RELNOTE_REQUIRED.format(args.module))
+        sys.exit(1)
+
+    sys.exit(0)
+
+if __name__ == '__main__':
+  main()
\ No newline at end of file
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 5b7b2a45..7a218f8 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -249,7 +249,7 @@
     docs(project(":navigation:navigation-fragment"))
     docs(project(":navigation:navigation-fragment-compose"))
     docs(project(":navigation:navigation-fragment-ktx"))
-    docs(project(":navigation:navigation-runtime"))
+    kmpDocs(project(":navigation:navigation-runtime"))
     docs(project(":navigation:navigation-runtime-ktx"))
     docs(project(":navigation:navigation-testing"))
     docs(project(":navigation:navigation-ui"))
diff --git a/docs/testing.md b/docs/testing.md
index b5b031f..95ae6b4 100644
--- a/docs/testing.md
+++ b/docs/testing.md
@@ -27,14 +27,13 @@
 pre-release API level.
 
 In practice, this is limited by device and emulator availability and
-reliability. As of November 2023, we run tests on the following API levels:
+reliability. As of January 2025, we run tests on the following API levels:
 
 -   API level 21: the lowest API level supported by Firebase Test Lab (FTL)
 -   API level 26: the lowest supported ARM-based emulator FTL runner, which has
     much greater performance and stability
--   API level 28: provides coverage between 26 and 30
--   API levels 30, 31, 33: the latest supported API levels, which represent the
-    majority of devices in the field
+-   API levels 30, 33, 34, 35: the latest supported API levels, which represent
+    the majority of devices in the field
 
 ## Adding tests {#adding}
 
@@ -433,9 +432,10 @@
 # Run instrumentation tests in Firebase Test Lab (remote)
 ./gradlew <project-name>:ftlnexus4api21
 ./gradlew <project-name>:ftlpixel2api26
-./gradlew <project-name>:ftlpixel2api28
 ./gradlew <project-name>:ftlpixel2api30
 ./gradlew <project-name>:ftlpixel2api33
+./gradlew <project-name>:ftlmediumphoneapi34
+./gradlew <project-name>:ftlmediumphoneapi35
 
 # Run local unit tests
 ./gradlew <project-name>:test
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
index 99d7e6f..1f9d6a8 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLManagerTest.kt
@@ -62,7 +62,6 @@
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
-@Suppress("AcronymName")
 class EGLManagerTest {
 
     @Test
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
index 622f973..ce80fb8 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/opengl/egl/EGLTestActivity.kt
@@ -33,7 +33,6 @@
 
 const val TAG: String = "EGLTestActivity"
 
-@Suppress("AcronymName")
 class EGLTestActivity : Activity() {
 
     private val mGLRenderer = GLRenderer()
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
index 2fd880c..659b5a7 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/lowlatency/GLFrontBufferedRenderer.kt
@@ -74,7 +74,6 @@
  * https://developer.android.com/reference/android/hardware/HardwareBuffer
  */
 @RequiresApi(Build.VERSION_CODES.Q)
-@Suppress("AcronymName")
 class GLFrontBufferedRenderer<T>
 @JvmOverloads
 constructor(
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
index 2a1683a..bad5d25 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLFrameBufferRenderer.kt
@@ -48,7 +48,6 @@
  * buffers as well as fine grained control over synchronization of buffer content.
  */
 @RequiresApi(Build.VERSION_CODES.Q)
-@Suppress("AcronymName")
 class GLFrameBufferRenderer
 internal constructor(
     private val surfaceControlProvider: SurfaceControlProvider,
@@ -195,7 +194,6 @@
          *   thread
          * @return The builder instance
          */
-        @Suppress("AcronymName")
         fun setGLRenderer(glRenderer: GLRenderer?): Builder {
             mGLRenderer = glRenderer
             return this
@@ -339,7 +337,7 @@
      * OpenGL.
      */
     val glRenderer: GLRenderer
-        @Suppress("AcronymName") @JvmName("getGLRenderer") get() = mGLRenderer
+        @JvmName("getGLRenderer") get() = mGLRenderer
 
     /**
      * Returns the [SyncStrategy] used for determining when to create [SyncFenceCompat] objects in
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
index 40ec7af..a595864 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/GLRenderer.kt
@@ -43,7 +43,6 @@
  *   the EGL context. This is invoked on the GL Thread
  */
 // GL is the industry standard for referencing OpenGL vs Gl (lowercase l)
-@Suppress("AcronymName")
 class GLRenderer(
     eglSpecFactory: () -> EGLSpec = { EGLSpec.V14 },
     eglConfigFactory: EGLManager.() -> EGLConfig = {
@@ -265,7 +264,6 @@
      *
      * These callbacks are invoked on the backing thread.
      */
-    @Suppress("AcronymName")
     fun registerEGLContextCallback(callback: EGLContextCallback) {
         mEglContextCallback.add(callback)
         mGLThread?.addEGLCallback(callback)
@@ -277,7 +275,6 @@
      *
      * These callbacks are invoked on the backing thread
      */
-    @Suppress("AcronymName")
     fun unregisterEGLContextCallback(callback: EGLContextCallback) {
         mEglContextCallback.remove(callback)
         mGLThread?.removeEGLCallback(callback)
@@ -288,7 +285,6 @@
      * places to setup and tear down any dependencies that are used for drawing content within a
      * frame (ex. compiling shaders)
      */
-    @Suppress("AcronymName")
     interface EGLContextCallback {
 
         /**
@@ -297,7 +293,7 @@
          * called. This will be invoked after [GLRenderer.start].
          */
         // Suppressing CallbackMethodName due to b/238939160
-        @Suppress("AcronymName", "CallbackMethodName")
+        @Suppress("CallbackMethodName")
         @WorkerThread
         fun onEGLContextCreated(eglManager: EGLManager)
 
@@ -306,7 +302,7 @@
          * This is invoked after [GLRenderer.stop] is processed.
          */
         // Suppressing CallbackMethodName due to b/238939160
-        @Suppress("AcronymName", "CallbackMethodName")
+        @Suppress("CallbackMethodName")
         @WorkerThread
         fun onEGLContextDestroyed(eglManager: EGLManager)
     }
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
index d609721..86f1b5c 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLConfigAttributes.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:Suppress("AcronymName")
-
 package androidx.graphics.opengl.egl
 
 import android.opengl.EGL14
@@ -89,7 +87,6 @@
  * }
  * ```
  */
-@Suppress("AcronymName")
 class EGLConfigAttributes internal constructor(@PublishedApi internal val attrs: IntArray) {
 
     /**
@@ -197,7 +194,6 @@
          * EGL Attributes to create an 8 bit EGL config for red, green, blue, and alpha channels as
          * well as an 8 bit stencil size
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_8888 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
@@ -215,7 +211,6 @@
          * EGL Attributes to create a 10 bit EGL config for red, green, blue, channels and a 2 bit
          * alpha channels. This does not include any bits for depth and stencil buffers.
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_1010102 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
@@ -232,7 +227,6 @@
          * EGL Attributes to create a 16 bit floating point EGL config for red, green, blue and
          * alpha channels without a depth or stencil channel.
          */
-        @Suppress("AcronymName")
         @JvmField
         val RGBA_F16 = EGLConfigAttributes {
             EGL14.EGL_RENDERABLE_TYPE to EGL14.EGL_OPENGL_ES2_BIT
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
index 7540cf3..68afce4e 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLManager.kt
@@ -28,7 +28,6 @@
  * Class responsible for configuration of EGL related resources. This includes initialization of the
  * corresponding EGL Display as well as EGL Context, among other EGL related facilities.
  */
-@Suppress("AcronymName")
 class EGLManager(eglSpec: EGLSpec = EGLSpec.V14) {
 
     private var mEglConfig: EGLConfig? = null
@@ -124,27 +123,27 @@
     }
 
     val eglSpec: EGLSpec
-        @Suppress("AcronymName") @JvmName("getEGLSpec") get() = mEglSpec
+        @JvmName("getEGLSpec") get() = mEglSpec
 
     /**
      * Returns the EGL version that is supported. This parameter is configured after [initialize] is
      * invoked.
      */
     val eglVersion: EGLVersion
-        @Suppress("AcronymName") @JvmName("getEGLVersion") get() = mEglVersion
+        @JvmName("getEGLVersion") get() = mEglVersion
 
     /**
      * Returns the current EGLContext. This parameter is configured after [initialize] is invoked
      */
     val eglContext: EGLContext?
-        @Suppress("AcronymName") @JvmName("getEGLContext") get() = mEglContext
+        @JvmName("getEGLContext") get() = mEglContext
 
     /**
      * Returns the [EGLConfig] used to load the current [EGLContext]. This is configured after
      * [createContext] is invoked.
      */
     val eglConfig: EGLConfig?
-        @Suppress("AcronymName") @JvmName("getEGLConfig") get() = mEglConfig
+        @JvmName("getEGLConfig") get() = mEglConfig
 
     /**
      * Determines whether the extension with the provided name is supported. The string provided is
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
index a233503..fdc7e4f 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/opengl/egl/EGLSpec.kt
@@ -45,7 +45,6 @@
  *
  * EGLSpec is not thread safe and is up to the caller of these methods to guarantee thread safety.
  */
-@Suppress("AcronymName")
 interface EGLSpec {
 
     /**
@@ -224,7 +223,6 @@
      *
      * See www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
      */
-    @Suppress("AcronymName")
     @RequiresApi(Build.VERSION_CODES.O)
     fun eglCreateImageFromHardwareBuffer(hardwareBuffer: HardwareBuffer): EGLImageKHR?
 
@@ -240,7 +238,7 @@
      * @param image EGLImageKHR to be destroyed
      * @return `true` if the destruction of the EGLImageKHR object was successful, `false` otherwise
      */
-    @Suppress("AcronymName") fun eglDestroyImageKHR(image: EGLImageKHR): Boolean
+    fun eglDestroyImageKHR(image: EGLImageKHR): Boolean
 
     /**
      * Creates a sync object of the specified type associated with the specified display, and
@@ -260,7 +258,6 @@
      * @return the [EGLSyncKHR] object to be used as a fence or null if this extension is not
      *   supported
      */
-    @Suppress("AcronymName")
     fun eglCreateSyncKHR(type: Int, attributes: EGLConfigAttributes?): EGLSyncKHR?
 
     /**
@@ -280,7 +277,6 @@
      *   not matching the display that was used to create this sync object. Additionally if the
      *   queried attribute is not supported for the sync object, false is returned.
      */
-    @Suppress("AcronymName")
     fun eglGetSyncAttribKHR(
         sync: EGLSyncKHR,
         @EGLSyncAttribute attribute: Int,
@@ -301,7 +297,7 @@
      *   or if the display provided in this method does not match the display used to create this
      *   sync in [eglCreateSyncKHR].
      */
-    @Suppress("AcronymName") fun eglDestroySyncKHR(sync: EGLSyncKHR): Boolean
+    fun eglDestroySyncKHR(sync: EGLSyncKHR): Boolean
 
     /**
      * Blocks the calling thread until the specified sync object is signalled or until
@@ -342,7 +338,6 @@
      *   [EGL_TIMEOUT_EXPIRED_KHR] if the sync did not signal within the specified timeout, or
      *   [EGL_FALSE] if an error occurs.
      */
-    @Suppress("AcronymName")
     fun eglClientWaitSyncKHR(
         sync: EGLSyncKHR,
         flags: Int,
@@ -550,7 +545,6 @@
  * @param error Error code reported via eglGetError
  * @param msg Optional message describing the exception being thrown
  */
-@Suppress("AcronymName")
 class EGLException(val error: Int, val msg: String = "") : RuntimeException() {
 
     override val message: String
@@ -563,7 +557,6 @@
  * @param major Major version of the EGL implementation
  * @param minor Minor version of the EGL implementation
  */
-@Suppress("AcronymName")
 data class EGLVersion(val major: Int, val minor: Int) {
 
     override fun toString(): String {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
index 182f845..0cc0d41 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
@@ -58,7 +58,6 @@
          *
          * Various transformations that can be applied to a buffer.
          */
-        @Suppress("AcronymName")
         @IntDef(
             value =
                 [
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
index 299c046..757b98b 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLExt.kt
@@ -28,7 +28,6 @@
 import androidx.opengl.EGLExt.Companion.eglCreateSyncKHR
 
 /** Utility class that provides some helper methods for interacting EGL Extension APIs */
-@Suppress("AcronymName")
 class EGLExt private constructor() {
 
     companion object {
@@ -191,7 +190,6 @@
 
         /** Specifies the types of attributes that can be queried in [eglGetSyncAttribKHR] */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_SYNC_TYPE_KHR, EGL_SYNC_STATUS_KHR, EGL_SYNC_CONDITION_KHR])
         annotation class EGLSyncAttribute
 
@@ -246,7 +244,6 @@
 
         /** Specifies the type of fence to create in [eglCreateSyncKHR] */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_SYNC_FENCE_KHR, EGL_SYNC_NATIVE_FENCE_ANDROID])
         annotation class EGLFenceType
 
@@ -290,7 +287,6 @@
         /** Specifies various return values for the [eglClientWaitSyncKHR] method */
         @RestrictTo(RestrictTo.Scope.LIBRARY)
         @Target(AnnotationTarget.TYPE)
-        @Suppress("AcronymName")
         @IntDef(value = [EGL_CONDITION_SATISFIED_KHR, EGL_TIMEOUT_EXPIRED_KHR, EGL_FALSE])
         annotation class EGLClientWaitResult
 
@@ -368,7 +364,6 @@
          * @return True if the destruction of the EGLImageKHR object was successful, false otherwise
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglDestroyImageKHR(eglDisplay: EGLDisplay, image: EGLImageKHR): Boolean =
             EGLBindings.nDestroyImageKHR(eglDisplay.nativeHandle, image.nativeHandle)
 
@@ -406,7 +401,6 @@
          *   supported
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglCreateSyncKHR(
             eglDisplay: EGLDisplay,
             @EGLFenceType type: Int,
@@ -441,7 +435,6 @@
          *   returned.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglGetSyncAttribKHR(
             eglDisplay: EGLDisplay,
             sync: EGLSyncKHR,
@@ -498,7 +491,6 @@
          *   [EGL_FALSE] if an error occurs.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglClientWaitSyncKHR(
             eglDisplay: EGLDisplay,
             sync: EGLSyncKHR,
@@ -557,7 +549,6 @@
          *   this sync in eglCreateSyncKHR.
          */
         @JvmStatic
-        @Suppress("AcronymName")
         fun eglDestroySyncKHR(eglDisplay: EGLDisplay, eglSync: EGLSyncKHR): Boolean =
             EGLBindings.nDestroySyncKHR(eglDisplay.nativeHandle, eglSync.nativeHandle)
 
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
index 6c66383..8b30e32 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLHandle.kt
@@ -17,7 +17,6 @@
 package androidx.opengl
 
 /** Interface used to wrap native EGL objects to create type safe objects */
-@Suppress("AcronymName")
 interface EGLHandle {
     /**
      * Returns the native handle of the wrapped EGL object. This handle can be cast to the
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
index 84ea358..eaea90d 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLImageKHR.kt
@@ -21,7 +21,6 @@
  * APIs). This is similar to EGL's EGLImage API except the KHR suffix indicates it is generated as
  * part of the extension APIs namely through [EGLExt.eglCreateImageFromHardwareBuffer]
  */
-@Suppress("AcronymName")
 class EGLImageKHR(override val nativeHandle: Long) : EGLHandle {
 
     override fun equals(other: Any?): Boolean {
diff --git a/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt b/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
index 3b20756..fc90ac4 100644
--- a/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
+++ b/graphics/graphics-core/src/main/java/androidx/opengl/EGLSyncKHR.kt
@@ -21,7 +21,6 @@
  * suffix indicates it is generated as part of the extension APIs namely through
  * [EGLExt.eglCreateSyncKHR].
  */
-@Suppress("AcronymName")
 class EGLSyncKHR(override val nativeHandle: Long) : EGLHandle {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
diff --git a/inspection/inspection/build.gradle b/inspection/inspection/build.gradle
index af4ba30..b721a23 100644
--- a/inspection/inspection/build.gradle
+++ b/inspection/inspection/build.gradle
@@ -30,6 +30,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api("androidx.annotation:annotation:1.8.1")
     androidTestImplementation(libs.kotlinStdlib)
     androidTestImplementation(libs.testCore)
@@ -46,8 +47,6 @@
     description = "Experimental AndroidX Inspection Project"
     legacyDisableKotlinStrictApiMode = true
     doNotDocumentReason = "Not shipped externally"
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
 
 android {
diff --git a/inspection/inspection/src/main/java/androidx/inspection/ArtTooling.java b/inspection/inspection/src/main/java/androidx/inspection/ArtTooling.java
index 3727a8b..03ca297 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/ArtTooling.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/ArtTooling.java
@@ -16,8 +16,8 @@
 
 package androidx.inspection;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 import java.util.List;
 
@@ -33,8 +33,7 @@
      * @param clazz class whose instances should be looked up
      * @return a list of instances of {@code clazz}
      */
-    @NonNull
-    <T> List<T> findInstances(@NonNull Class<T> clazz);
+    <T> @NonNull List<T> findInstances(@NonNull Class<T> clazz);
 
     /**
      * A callback invoked at the entry to an instrumented method.
diff --git a/inspection/inspection/src/main/java/androidx/inspection/ArtToolingImpl.java b/inspection/inspection/src/main/java/androidx/inspection/ArtToolingImpl.java
index 04a70dd..9185d2d 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/ArtToolingImpl.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/ArtToolingImpl.java
@@ -18,12 +18,13 @@
 
 import android.annotation.SuppressLint;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.inspection.ArtTooling.EntryHook;
 import androidx.inspection.ArtTooling.ExitHook;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -46,8 +47,7 @@
      * We don't have a way to undo bytecode manipulations, so to avoid duplicating doing the same
      * transformations multiple times, this object lives forever.
      */
-    @NonNull
-    public static ArtToolingImpl instance() {
+    public static @NonNull ArtToolingImpl instance() {
         if (sInstance == null) {
             System.loadLibrary("art_tooling");
             sInstance = new ArtToolingImpl(createNativeArtTooling());
@@ -84,8 +84,7 @@
     /**
      * Called from DefaultArtTooling
      */
-    @NonNull
-    public static <T> List<T> findInstances(@NonNull Class<T> clazz) {
+    public static <T> @NonNull List<T> findInstances(@NonNull Class<T> clazz) {
         return Arrays.asList(nativeFindInstances(instance().mNativePtr, clazz));
     }
 
@@ -150,8 +149,8 @@
     }
 
     /** Callback from native */
-    @Nullable
-    public static Object onExit(@NonNull String methodSignature, @Nullable Object returnObject) {
+    public static @Nullable Object onExit(@NonNull String methodSignature,
+            @Nullable Object returnObject) {
         return onExitInternal(methodSignature, returnObject);
     }
 
@@ -213,7 +212,7 @@
      * receive the array: ["(Lcom/example/Receiver;Ljava/lang/String;)Lcom/example/Client;", this,
      * r, message]
      */
-    public static void onEntry(@NonNull Object[] signatureThisParams) {
+    public static void onEntry(Object @NonNull [] signatureThisParams) {
         // Should always at least contain signature and "this"
         assert (signatureThisParams.length >= 2);
         String signature = (String) signatureThisParams[0];
diff --git a/inspection/inspection/src/main/java/androidx/inspection/Connection.java b/inspection/inspection/src/main/java/androidx/inspection/Connection.java
index fd0c3f2..cd309ee 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/Connection.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/Connection.java
@@ -16,7 +16,7 @@
 
 package androidx.inspection;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * A class representing a connection between studio and inspectors.
@@ -28,6 +28,6 @@
      *
      * @param data An array of bytes. Up to inspectors to determine how to encode bytes.
      */
-    public void sendEvent(@NonNull byte[] data) {
+    public void sendEvent(byte @NonNull [] data) {
     }
 }
diff --git a/inspection/inspection/src/main/java/androidx/inspection/DefaultArtTooling.java b/inspection/inspection/src/main/java/androidx/inspection/DefaultArtTooling.java
index fcceef9..6a67de7 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/DefaultArtTooling.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/DefaultArtTooling.java
@@ -16,9 +16,10 @@
 
 package androidx.inspection;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.List;
 
 /**
@@ -32,9 +33,8 @@
         mInspectorId = inspectorId;
     }
 
-    @NonNull
     @Override
-    public <T> List<T> findInstances(@NonNull Class<T> clazz) {
+    public <T> @NonNull List<T> findInstances(@NonNull Class<T> clazz) {
         return ArtToolingImpl.findInstances(clazz);
     }
 
diff --git a/inspection/inspection/src/main/java/androidx/inspection/Inspector.java b/inspection/inspection/src/main/java/androidx/inspection/Inspector.java
index f512df2..fe0506d 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/Inspector.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/Inspector.java
@@ -18,7 +18,7 @@
 
 import android.annotation.SuppressLint;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 import java.util.concurrent.Executor;
 
@@ -30,8 +30,7 @@
  */
 public abstract class Inspector {
 
-    @NonNull
-    private Connection mConnection;
+    private @NonNull Connection mConnection;
 
     /**
      * @param connection a connection object that allows to send events to studio
@@ -57,13 +56,12 @@
      * @param data a raw byte array of the command sent by studio.
      * @param callback a callback to reply on the given command.
      */
-    public abstract void onReceiveCommand(@NonNull byte[] data, @NonNull CommandCallback callback);
+    public abstract void onReceiveCommand(byte @NonNull [] data, @NonNull CommandCallback callback);
 
     /**
      * Returns a connection that allows to send events to Studio.
      */
-    @NonNull
-    protected final Connection getConnection() {
+    protected final @NonNull Connection getConnection() {
         return mConnection;
     }
 
@@ -78,7 +76,7 @@
          */
         // Users don't implement this callback, but call methods on it themselves
         @SuppressLint("CallbackMethodName")
-        void reply(@NonNull byte[] response);
+        void reply(byte @NonNull [] response);
 
         /**
          * Handles a signal sent from Studio that this command should be cancelled, if possible.
diff --git a/inspection/inspection/src/main/java/androidx/inspection/InspectorEnvironment.java b/inspection/inspection/src/main/java/androidx/inspection/InspectorEnvironment.java
index c8b22eb..e70c992 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/InspectorEnvironment.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/InspectorEnvironment.java
@@ -16,7 +16,7 @@
 
 package androidx.inspection;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * This interface provides inspector specific utilities, such as
@@ -28,14 +28,12 @@
      * Executors provided by App Inspection Platforms. Clients should use it instead of
      * creating their own.
      */
-    @NonNull
-    default InspectorExecutors executors() {
+    default @NonNull InspectorExecutors executors() {
         throw new UnsupportedOperationException();
     }
 
     /**
      * Interface that provides ART TI capabilities.
      */
-    @NonNull
-    ArtTooling artTooling();
+    @NonNull ArtTooling artTooling();
 }
diff --git a/inspection/inspection/src/main/java/androidx/inspection/InspectorExecutors.java b/inspection/inspection/src/main/java/androidx/inspection/InspectorExecutors.java
index 4bb081e..09ebfa5 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/InspectorExecutors.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/InspectorExecutors.java
@@ -18,7 +18,7 @@
 
 import android.os.Handler;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 import java.util.concurrent.Executor;
 
@@ -57,8 +57,7 @@
      * Even when a future wasn't dropped or lost, developers would still need to block one
      * of the threads.
      */
-    @NonNull
-    Handler handler();
+    @NonNull Handler handler();
 
     /**
      * Primary single threaded executor for the given inspector.
@@ -70,12 +69,10 @@
      * It is important to keep this executor responsive, so it can quickly process incoming
      * messages.
      */
-    @NonNull
-    Executor primary();
+    @NonNull Executor primary();
 
     /**
      * An executor for offloading blocking IO tasks to a shared pool of threads.
      */
-    @NonNull
-    Executor io();
+    @NonNull Executor io();
 }
diff --git a/inspection/inspection/src/main/java/androidx/inspection/InspectorFactory.java b/inspection/inspection/src/main/java/androidx/inspection/InspectorFactory.java
index 2f4c253..cbf8399 100644
--- a/inspection/inspection/src/main/java/androidx/inspection/InspectorFactory.java
+++ b/inspection/inspection/src/main/java/androidx/inspection/InspectorFactory.java
@@ -16,7 +16,7 @@
 
 package androidx.inspection;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
 /**
  * A factory that is responsible for creation of an inspector for your library.
@@ -42,8 +42,7 @@
     /**
      * @return an id of an inspector that is served by this factory.
      */
-    @NonNull
-    public final String getInspectorId() {
+    public final @NonNull String getInspectorId() {
         return mInspectorId;
     }
 
@@ -54,7 +53,6 @@
      * @param environment an environment that provides tooling utilities.
      * @return a new instance of an inspector.
      */
-    @NonNull
-    public abstract T createInspector(@NonNull Connection connection,
+    public abstract @NonNull T createInspector(@NonNull Connection connection,
             @NonNull InspectorEnvironment environment);
 }
diff --git a/libraryversions.toml b/libraryversions.toml
index 7e33193..3e4aed9 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,5 +1,5 @@
 [versions]
-ACTIVITY = "1.10.0-rc01"
+ACTIVITY = "1.11.0-alpha01"
 ANNOTATION = "1.9.0-rc01"
 ANNOTATION_EXPERIMENTAL = "1.5.0-alpha01"
 APPCOMPAT = "1.8.0-alpha01"
@@ -8,7 +8,7 @@
 ARCH_CORE = "2.3.0-alpha01"
 ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
 AUTOFILL = "1.3.0-rc01"
-BENCHMARK = "1.4.0-alpha06"
+BENCHMARK = "1.4.0-alpha07"
 BIOMETRIC = "1.4.0-alpha02"
 BLUETOOTH = "1.0.0-alpha02"
 BROWSER = "1.9.0-alpha01"
@@ -22,8 +22,8 @@
 CAR_APP = "1.8.0-alpha01"
 COLLECTION = "1.5.0-beta02"
 COMPOSE = "1.8.0-alpha08"
-COMPOSE_MATERIAL3 = "1.4.0-alpha06"
-COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha09"
+COMPOSE_MATERIAL3 = "1.4.0-alpha07"
+COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-beta01"
 COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
 COMPOSE_MATERIAL3_XR = "1.0.0-alpha02"
 COMPOSE_RUNTIME = "1.8.0-beta01"
@@ -95,14 +95,14 @@
 LEANBACK_TAB = "1.1.0-beta01"
 LEGACY = "1.1.0-alpha01"
 LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.9.0-alpha08"
+LIFECYCLE = "2.9.0-alpha09"
 LIFECYCLE_EXTENSIONS = "2.2.0"
 LINT = "1.0.0-alpha03"
 LOADER = "1.2.0-alpha01"
 MEDIA = "1.8.0-alpha01"
 MEDIAROUTER = "1.8.0-alpha02"
 METRICS = "1.0.0-beta02"
-NAVIGATION = "2.9.0-alpha04"
+NAVIGATION = "2.9.0-alpha05"
 NAVIGATION3 = "0.1.0-dev01"
 PAGING = "3.4.0-alpha01"
 PALETTE = "1.1.0-alpha01"
@@ -125,14 +125,14 @@
 RESOURCEINSPECTION = "1.1.0-alpha01"
 ROOM = "2.7.0-alpha12"
 SAFEPARCEL = "1.0.0-alpha01"
-SAVEDSTATE = "1.3.0-alpha06"
+SAVEDSTATE = "1.3.0-alpha07"
 SECURITY = "1.1.0-alpha07"
 SECURITY_APP_AUTHENTICATOR = "1.0.0-rc01"
 SECURITY_APP_AUTHENTICATOR_TESTING = "1.0.0-rc01"
 SECURITY_BIOMETRIC = "1.0.0-alpha01"
 SECURITY_IDENTITY_CREDENTIAL = "1.0.0-alpha04"
 SECURITY_MLS = "1.0.0-alpha01"
-SECURITY_STATE = "1.0.0-alpha04"
+SECURITY_STATE = "1.0.0-alpha05"
 SECURITY_STATE_PROVIDER = "1.0.0-alpha01"
 SHARETARGET = "1.3.0-alpha01"
 SLICE = "1.1.0-alpha03"
@@ -174,7 +174,7 @@
 WEAR_TILES = "1.5.0-alpha07"
 WEAR_TOOLING_PREVIEW = "1.0.0-rc01"
 WEAR_WATCHFACE = "1.3.0-alpha05"
-WEBKIT = "1.13.0-alpha03"
+WEBKIT = "1.13.0-beta01"
 # Adding a comment to prevent merge conflicts for Window artifact
 WINDOW = "1.4.0-beta01"
 WINDOW_EXTENSIONS = "1.4.0-rc01"
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/current.txt b/lifecycle/lifecycle-viewmodel-compose/api/current.txt
index ace8748..8372225 100644
--- a/lifecycle/lifecycle-viewmodel-compose/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-compose/api/current.txt
@@ -29,3 +29,12 @@
 
 }
 
+package androidx.lifecycle.viewmodel.compose.serialization.serializers {
+
+  public final class MutableStateSerializerKt {
+    method public static inline <reified T> kotlinx.serialization.KSerializer<androidx.compose.runtime.MutableState<T>> MutableStateSerializer();
+    method public static <T> kotlinx.serialization.KSerializer<androidx.compose.runtime.MutableState<T>> MutableStateSerializer(kotlinx.serialization.KSerializer<T> serializer);
+  }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.txt
index ace8748..8372225 100644
--- a/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.txt
@@ -29,3 +29,12 @@
 
 }
 
+package androidx.lifecycle.viewmodel.compose.serialization.serializers {
+
+  public final class MutableStateSerializerKt {
+    method public static inline <reified T> kotlinx.serialization.KSerializer<androidx.compose.runtime.MutableState<T>> MutableStateSerializer();
+    method public static <T> kotlinx.serialization.KSerializer<androidx.compose.runtime.MutableState<T>> MutableStateSerializer(kotlinx.serialization.KSerializer<T> serializer);
+  }
+
+}
+
diff --git a/lifecycle/lifecycle-viewmodel-compose/build.gradle b/lifecycle/lifecycle-viewmodel-compose/build.gradle
index c63ee18..6b1230c 100644
--- a/lifecycle/lifecycle-viewmodel-compose/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-compose/build.gradle
@@ -30,6 +30,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("AndroidXComposePlugin")
+    alias(libs.plugins.kotlinSerialization)
 }
 
 androidXMultiplatform {
@@ -45,12 +46,17 @@
                 api(project(":lifecycle:lifecycle-viewmodel"))
                 api("androidx.annotation:annotation:1.8.1")
                 api("androidx.compose.runtime:runtime:1.6.0")
+                api(libs.kotlinSerializationCore)
                 implementation(libs.kotlinStdlib)
             }
         }
 
         commonTest {
-            // TODO(b/330323282): Move common dependencies here.
+            dependencies {
+                implementation(project(":lifecycle:lifecycle-viewmodel-savedstate"))
+                implementation(project(":lifecycle:lifecycle-viewmodel-testing"))
+                implementation(project(":lifecycle:lifecycle-runtime-testing"))
+            }
         }
 
         androidMain {
@@ -83,9 +89,7 @@
                 // but it doesn't work in androidx.
                 // See aosp/1804059
                 implementation(project(":lifecycle:lifecycle-common-java8"))
-                implementation(project(":lifecycle:lifecycle-viewmodel-savedstate"))
                 implementation(project(":activity:activity-compose"))
-                implementation(project(":lifecycle:lifecycle-runtime-testing"))
             }
         }
     }
diff --git a/lifecycle/lifecycle-viewmodel-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializerTest.android.kt b/lifecycle/lifecycle-viewmodel-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializerTest.android.kt
new file mode 100644
index 0000000..0cbeb73
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-compose/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializerTest.android.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.lifecycle.viewmodel.compose.serialization.serializers
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.savedstate.serialization.decodeFromSavedState
+import androidx.savedstate.serialization.encodeToSavedState
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.serializer
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MutableStateSerializerTest {
+
+    @Test
+    fun encodeDecode_withImplicitSerializer() {
+        val state = mutableStateOf(USER_JOHN_DOE)
+        val serializer = MutableStateSerializer<User>()
+
+        val encoded = encodeToSavedState(serializer, state)
+        val decoded = decodeFromSavedState(serializer, encoded)
+
+        assertThat(state.value).isEqualTo(decoded.value)
+    }
+
+    @Test
+    fun encodeDecode_withExplicitSerializer() {
+        val state = mutableStateOf(USER_JOHN_DOE)
+        val serializer = MutableStateSerializer(USER_SERIALIZER)
+
+        val encoded = encodeToSavedState(serializer, state)
+        val decoded = decodeFromSavedState(serializer, encoded)
+
+        assertThat(state.value).isEqualTo(decoded.value)
+    }
+
+    companion object {
+        val USER_JOHN_DOE = User(name = "John", surname = "Doe")
+        @OptIn(InternalSerializationApi::class) val USER_SERIALIZER = User::class.serializer()
+    }
+
+    @Serializable data class User(val name: String = "John", val surname: String = "Doe")
+}
diff --git a/lifecycle/lifecycle-viewmodel-compose/src/commonMain/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializer.kt b/lifecycle/lifecycle-viewmodel-compose/src/commonMain/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializer.kt
new file mode 100644
index 0000000..1bd43bd
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel-compose/src/commonMain/kotlin/androidx/lifecycle/viewmodel/compose/serialization/serializers/MutableStateSerializer.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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:OptIn(InternalSerializationApi::class, ExperimentalTypeInference::class)
+
+package androidx.lifecycle.viewmodel.compose.serialization.serializers
+
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import kotlin.experimental.ExperimentalTypeInference
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.serializer
+
+/**
+ * Creates a [KSerializer] for a [MutableState] containing a [Serializable] value of type [T].
+ *
+ * This inline function infers the state type [T] automatically and retrieves the appropriate
+ * [KSerializer] for serialization and deserialization of [MutableState].
+ *
+ * @param T The type of the value stored in the [MutableState].
+ * @return A [KSerializer] for handling [MutableState] containing a [Serializable] type [T].
+ */
+@Suppress("FunctionName")
+public inline fun <reified T> MutableStateSerializer(): KSerializer<MutableState<T>> {
+    return MutableStateSerializer(serializer())
+}
+
+/**
+ * Creates a [KSerializer] for a [MutableState] containing a [Serializable] value of type [T].
+ *
+ * This function allows for explicit specification of the [KSerializer] for the state type [T]. It
+ * provides serialization and deserialization capabilities for [MutableState] objects.
+ *
+ * @param T The type of the value stored in the [MutableState].
+ * @param serializer The [KSerializer] for the [Serializable] type [T].
+ * @return A [KSerializer] for handling [MutableState] containing a [Serializable] type [T].
+ */
+@Suppress("FunctionName")
+public fun <T> MutableStateSerializer(serializer: KSerializer<T>): KSerializer<MutableState<T>> {
+    return MutableStateSerializerImpl<T>(serializer)
+}
+
+/**
+ * Internal implementation of [KSerializer] for [MutableState].
+ *
+ * This private class wraps a [KSerializer] for the inner value type [T], enabling serialization and
+ * deserialization of [MutableState] instances. The inner value serialization is delegated to the
+ * provided [valueSerializer].
+ *
+ * @param T The type of the value stored in the [MutableState].
+ * @property valueSerializer The [KSerializer] used to serialize and deserialize the inner value.
+ */
+private class MutableStateSerializerImpl<T>(
+    private val valueSerializer: KSerializer<T>,
+) : KSerializer<MutableState<T>> {
+
+    override val descriptor: SerialDescriptor = valueSerializer.descriptor
+
+    override fun serialize(encoder: Encoder, value: MutableState<T>) {
+        valueSerializer.serialize(encoder, value.value)
+    }
+
+    override fun deserialize(decoder: Decoder): MutableState<T> {
+        return mutableStateOf(valueSerializer.deserialize(decoder))
+    }
+}
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt b/lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProviderTest.kt
similarity index 100%
rename from lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapperTest.kt
rename to lifecycle/lifecycle-viewmodel-navigation3/src/androidInstrumentedTest/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProviderTest.kt
diff --git a/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt b/lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt
similarity index 100%
rename from lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavContentWrapper.android.kt
rename to lifecycle/lifecycle-viewmodel-navigation3/src/androidMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavLocalProvider.android.kt
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
index 74041ee..e9b8ced 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
@@ -50,10 +50,8 @@
 package androidx.lifecycle.serialization {
 
   public final class SavedStateHandleDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
index 74041ee..e9b8ced 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
@@ -50,10 +50,8 @@
 package androidx.lifecycle.serialization {
 
   public final class SavedStateHandleDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.lifecycle.SavedStateHandle, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
index 7a78cde..3b9bf81 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/bcv/native/current.txt
@@ -42,7 +42,5 @@
 
 final fun (androidx.lifecycle.viewmodel/CreationExtras).androidx.lifecycle/createSavedStateHandle(): androidx.lifecycle/SavedStateHandle // androidx.lifecycle/createSavedStateHandle|createSavedStateHandle@androidx.lifecycle.viewmodel.CreationExtras(){}[0]
 final fun <#A: androidx.lifecycle/ViewModelStoreOwner & androidx.savedstate/SavedStateRegistryOwner> (#A).androidx.lifecycle/enableSavedStateHandles() // androidx.lifecycle/enableSavedStateHandles|enableSavedStateHandles@0:0(){0§<androidx.savedstate.SavedStateRegistryOwner&androidx.lifecycle.ViewModelStoreOwner>}[0]
-final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String, kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlin.String;kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String, noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlin.String;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final fun <#A: kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/String? = ..., kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlinx.serialization.KSerializer<0:0>;kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final inline fun <#A: reified kotlin/Any> (androidx.lifecycle/SavedStateHandle).androidx.lifecycle.serialization/saved(kotlin/String? = ..., noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.lifecycle.serialization/saved|saved@androidx.lifecycle.SavedStateHandle(kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
index a964d34..edd1bc10 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/commonMain/kotlin/androidx/lifecycle/serialization/SavedStateHandleDelegates.kt
@@ -27,67 +27,34 @@
 
 /**
  * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
- * with fully qualified property or variable name as key and the default serializer.
- *
- * @sample androidx.lifecycle.delegate
- * @param init The function to provide the initial value of the property.
- * @return A property delegate that manages the saving and restoring of the value.
- */
-public inline fun <reified T : Any> SavedStateHandle.saved(
-    noinline init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return saved(serializer(), init)
-}
-
-/**
- * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
  * with the default serializer.
  *
  * @sample androidx.lifecycle.delegateExplicitKey
- * @param key The [String] key to use for storing the value in the [SavedStateHandle].
+ * @param key An optional [String] key to use for storing the value in the [SavedStateHandle]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate that manages the saving and restoring of the value.
  */
 public inline fun <reified T : Any> SavedStateHandle.saved(
-    key: String,
+    key: String? = null,
     noinline init: () -> T,
 ): ReadWriteProperty<Any?, T> {
-    return saved(key, serializer(), init)
-}
-
-/**
- * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T]
- * with fully qualified property or variable name as key.
- *
- * @sample androidx.lifecycle.delegateExplicitSerializer
- * @param serializer The [KSerializer] to use for serializing and deserializing the value.
- * @param init The function to provide the initial value of the property.
- * @return A property delegate that manages the saving and restoring of the value.
- */
-public fun <T : Any> SavedStateHandle.saved(
-    serializer: KSerializer<T>,
-    init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return SavedStateHandleDelegate(
-        savedStateHandle = this,
-        key = null,
-        serializer = serializer,
-        init = init
-    )
+    return saved(serializer(), key, init)
 }
 
 /**
  * Returns a property delegate that uses [SavedStateHandle] to save and restore a value of type [T].
  *
  * @sample androidx.lifecycle.delegateExplicitKeyAndSerializer
- * @param key The [String] key to use for storing the value in the [SavedStateHandle].
  * @param serializer The [KSerializer] to use for serializing and deserializing the value.
+ * @param key An optional [String] key to use for storing the value in the [SavedStateHandle]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate that manages the saving and restoring of the value.
  */
 public fun <T : Any> SavedStateHandle.saved(
-    key: String,
     serializer: KSerializer<T>,
+    key: String? = null,
     init: () -> T,
 ): ReadWriteProperty<Any?, T> {
     return SavedStateHandleDelegate(
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
index 0a5ea75..f34aa4c 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
@@ -687,8 +687,9 @@
             // animating. In these cases the currentEntry will be null, and in those cases,
             // AnimatedContent will just skip attempting to transition the old entry.
             // See https://issuetracker.google.com/238686802
+            val isPredictiveBackCancelAnimation = transitionState.currentState == backStackEntry
             val currentEntry =
-                if (inPredictiveBack) {
+                if (inPredictiveBack || isPredictiveBackCancelAnimation) {
                     // We have to do this because the previous entry does not show up in
                     // visibleEntries
                     // even if we prepare it above as part of onBackStackChangeStarted
diff --git a/navigation/navigation-runtime/bcv/native/current.txt b/navigation/navigation-runtime/bcv/native/current.txt
new file mode 100644
index 0000000..47e0dc0
--- /dev/null
+++ b/navigation/navigation-runtime/bcv/native/current.txt
@@ -0,0 +1,11 @@
+// Klib ABI Dump
+// Targets: [iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64]
+// Rendering settings:
+// - Signature version: 2
+// - Show manifest properties: true
+// - Show declarations: true
+
+// Library unique name: <androidx.navigation:navigation-runtime>
+open annotation class androidx.navigation/NavDeepLinkSaveStateControl : kotlin/Annotation { // androidx.navigation/NavDeepLinkSaveStateControl|null[0]
+    constructor <init>() // androidx.navigation/NavDeepLinkSaveStateControl.<init>|<init>(){}[0]
+}
diff --git a/navigation/navigation-runtime/build.gradle b/navigation/navigation-runtime/build.gradle
index 1ad4631..c71a4c0 100644
--- a/navigation/navigation-runtime/build.gradle
+++ b/navigation/navigation-runtime/build.gradle
@@ -24,49 +24,132 @@
 
 import androidx.build.KotlinTarget
 import androidx.build.LibraryType
+import androidx.build.PlatformIdentifier
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("kotlin-android")
     alias(libs.plugins.kotlinSerialization)
 }
 
+androidXMultiplatform {
+    android()
+    desktop()
+    mac()
+    linux()
+    ios()
+
+    defaultPlatform(PlatformIdentifier.ANDROID)
+
+    sourceSets {
+        commonMain {
+            dependencies {
+                api(libs.kotlinStdlib)
+                api(libs.kotlinCoroutinesCore)
+                api(project(":navigation:navigation-common"))
+                api("androidx.lifecycle:lifecycle-common:2.6.2")
+                api("androidx.lifecycle:lifecycle-runtime:2.6.2")
+                api("androidx.lifecycle:lifecycle-viewmodel:2.6.2")
+
+                implementation(libs.kotlinSerializationCore)
+                implementation("androidx.collection:collection:1.4.2")
+            }
+        }
+        commonTest {
+            dependencies {
+                implementation(libs.kotlinTest)
+            }
+        }
+        nonAndroidMain {
+            dependsOn(commonMain)
+        }
+        nonAndroidTest {
+            dependsOn(commonTest)
+        }
+        jvmCommonMain {
+            dependsOn(commonMain)
+        }
+        jvmCommonTest {
+            dependsOn(commonTest)
+        }
+        desktopMain {
+            dependsOn(jvmCommonMain)
+            dependsOn(nonAndroidMain)
+        }
+        desktopTest {
+            dependsOn(jvmCommonTest)
+            dependsOn(nonAndroidTest)
+        }
+        androidMain {
+            dependsOn(jvmCommonMain)
+            dependencies {
+                api("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
+                api("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
+                api("androidx.activity:activity-ktx:1.7.1")
+                api("androidx.core:core-ktx:1.8.0")
+                api("androidx.annotation:annotation-experimental:1.4.1")
+            }
+        }
+        androidUnitTest {
+            dependsOn(commonTest)
+        }
+        androidInstrumentedTest {
+            dependsOn(commonTest)
+            dependencies {
+                implementation("androidx.annotation:annotation:1.8.0")
+                implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-common:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-runtime:2.6.2")
+                implementation("androidx.lifecycle:lifecycle-runtime-testing:2.6.2")
+                implementation(project(":internal-testutils-navigation"))
+                implementation(project(":internal-testutils-runtime"))
+                implementation(libs.hamcrestCore)
+                implementation(libs.junit)
+                implementation(libs.kotlinTest)
+                implementation(libs.testCore)
+                implementation(libs.testExtJunit)
+                implementation(libs.testExtTruth)
+                implementation(libs.testMonitor)
+                implementation(libs.testRunner)
+                implementation(libs.testRules)
+                implementation(libs.espressoIntents)
+                implementation(libs.truth)
+                implementation(libs.dexmakerMockito)
+                implementation(libs.mockitoCore)
+            }
+        }
+        nonJvmCommonMain {
+            dependsOn(nonAndroidMain)
+        }
+        nonJvmCommonTest {
+            dependsOn(nonAndroidTest)
+        }
+        nativeMain {
+            dependsOn(nonJvmCommonMain)
+        }
+        linuxMain.dependsOn(nativeMain)
+        darwinMain.dependsOn(nativeMain)
+        nativeTest {
+            dependsOn(nonJvmCommonTest)
+        }
+        linuxTest.dependsOn(nativeTest)
+        darwinTest.dependsOn(nativeTest)
+        targets.configureEach { target ->
+            if (target.platformType == KotlinPlatformType.native) {
+                if (target.konanTarget.family.appleFamily) {
+                    target.compilations["main"].defaultSourceSet.dependsOn(darwinMain)
+                    target.compilations["test"].defaultSourceSet.dependsOn(darwinTest)
+                } else if (target.konanTarget.family == org.jetbrains.kotlin.konan.target.Family.LINUX) {
+                    target.compilations["main"].defaultSourceSet.dependsOn(linuxMain)
+                    target.compilations["test"].defaultSourceSet.dependsOn(linuxTest)
+                }
+            }
+        }
+    }
+}
+
 dependencies {
-    api(libs.kotlinStdlib)
-    api(libs.kotlinCoroutinesCore)
-    api(project(":navigation:navigation-common"))
-    api("androidx.activity:activity-ktx:1.7.1")
-    api("androidx.core:core-ktx:1.8.0")
-    api("androidx.lifecycle:lifecycle-common:2.6.2")
-    api("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
-    api("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
-    api("androidx.annotation:annotation-experimental:1.4.1")
-
-    implementation(libs.kotlinSerializationCore)
-    implementation("androidx.collection:collection:1.4.2")
-
-    androidTestImplementation("androidx.annotation:annotation:1.8.0")
-    androidTestImplementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-common:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-runtime:2.6.2")
-    androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing:2.6.2")
-    androidTestImplementation(project(":internal-testutils-navigation"))
-    androidTestImplementation(project(":internal-testutils-runtime"))
-    androidTestImplementation(libs.hamcrestCore)
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.kotlinTest)
-    androidTestImplementation(libs.testCore)
-    androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testExtTruth)
-    androidTestImplementation(libs.testMonitor)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.espressoIntents)
-    androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.dexmakerMockito)
-    androidTestImplementation(libs.mockitoCore)
-
     lintPublish(project(":navigation:navigation-runtime-lint"))
 }
 
diff --git a/navigation/navigation-runtime/src/androidTest/AndroidManifest.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/AndroidManifest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/AndroidManifest.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/AndroidManifest.xml
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilderTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorExtrasTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorExtrasTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorExtrasTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorExtrasTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityNavigatorTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityNavigatorTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ActivityTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ActivityTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/FloatingWindowTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/FloatingWindowTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/FloatingWindowTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/FloatingWindowTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryLifecycleTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryLifecycleTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavBackStackEntryTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerActivityTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerActivityTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerActivityTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerActivityTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerRouteTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerRouteTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerViewModelTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerViewModelTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerViewModelTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavControllerViewModelTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavDeepLinkBuilderTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavDeepLinkBuilderTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavDeepLinkBuilderTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavHostTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavHostTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavHostTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavInflaterTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavInflaterTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/NavInflaterTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ViewTest.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ViewTest.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/ViewTest.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/ViewTest.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/FloatingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/FloatingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/FloatingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingFloatingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingFloatingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingFloatingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingFloatingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingTestNavigator.kt b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingTestNavigator.kt
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/SupportingTestNavigator.kt
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/SupportingTestNavigator.kt
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
similarity index 86%
rename from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
rename to navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
index f3a5276..11e2eb167 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
+++ b/navigation/navigation-runtime/src/androidInstrumentedTest/kotlin/androidx/navigation/test/TestEnum.kt
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.navigation.test;
+package androidx.navigation.test
 
-public enum TestEnum {
-    VALUE_ONE, VALUE_TWO
+public enum class TestEnum {
+    VALUE_ONE,
+    VALUE_TWO
 }
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_applicationid_arg.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_applicationid_arg.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_applicationid_arg.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_arguments.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_arguments.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_arguments.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_arguments.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_deeplink.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_deeplink.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_deeplink.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_deeplink.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_default_arguments.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_default_arguments.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_default_arguments.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_first.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_first.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_first.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_first.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_floating.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_floating.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_floating.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_floating.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_arg_type.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_arg_type.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_arg_type.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_arg_type.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_default_value.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_default_value.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_argument_default_value.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_argument_default_value.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_invalid_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_invalid_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_missing_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_missing_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_missing_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_missing_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_multiple_navigation.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_multiple_navigation.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_multiple_navigation.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_multiple_navigation.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_nested_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_nested_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_nested_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_nested_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_non_start_nest.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_non_start_nest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_non_start_nest.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_non_start_nest.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_root.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_root.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_root.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_root.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_second.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_second.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_second.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_second.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_simple.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_simple.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_simple.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_simple.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/navigation/nav_start_destination.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_start_destination.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/navigation/nav_start_destination.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/navigation/nav_start_destination.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/values/styles.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/values/styles.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/values/styles.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/values/styles.xml
diff --git a/navigation/navigation-runtime/src/androidTest/res/values/values.xml b/navigation/navigation-runtime/src/androidInstrumentedTest/res/values/values.xml
similarity index 100%
rename from navigation/navigation-runtime/src/androidTest/res/values/values.xml
rename to navigation/navigation-runtime/src/androidInstrumentedTest/res/values/values.xml
diff --git a/navigation/navigation-runtime/src/main/AndroidManifest.xml b/navigation/navigation-runtime/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/AndroidManifest.xml
rename to navigation/navigation-runtime/src/androidMain/AndroidManifest.xml
diff --git a/navigation/navigation-runtime/src/main/baseline-prof.txt b/navigation/navigation-runtime/src/androidMain/baseline-prof.txt
similarity index 100%
rename from navigation/navigation-runtime/src/main/baseline-prof.txt
rename to navigation/navigation-runtime/src/androidMain/baseline-prof.txt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/package-info.java b/navigation/navigation-runtime/src/androidMain/java/androidx/navigation/package-info.java
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/package-info.java
rename to navigation/navigation-runtime/src/androidMain/java/androidx/navigation/package-info.java
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
index 8bf71cd..a0f3b6b 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/Activity.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Activity.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
similarity index 95%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
index f1d9052..bf50861 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavArgsLazy.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavArgsLazy.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityNavArgsLazyKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigator.android.kt
similarity index 95%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigator.android.kt
index 4fb24ac..6838cad 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigator.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigator.android.kt
@@ -21,7 +21,6 @@
 import android.content.ContextWrapper
 import android.content.Intent
 import android.net.Uri
-import android.os.Bundle
 import android.util.AttributeSet
 import android.util.Log
 import androidx.annotation.CallSuper
@@ -29,6 +28,8 @@
 import androidx.core.app.ActivityCompat
 import androidx.core.app.ActivityOptionsCompat
 import androidx.core.content.res.use
+import androidx.savedstate.SavedState
+import androidx.savedstate.read
 import java.util.regex.Pattern
 
 /** ActivityNavigator implements cross-activity navigation. */
@@ -75,7 +76,7 @@
     @Suppress("DEPRECATION")
     override fun navigate(
         destination: Destination,
-        args: Bundle?,
+        args: SavedState?,
         navOptions: NavOptions?,
         navigatorExtras: Navigator.Extras?
     ): NavDestination? {
@@ -92,17 +93,19 @@
                 val fillInPattern = Pattern.compile("\\{(.+?)\\}")
                 val matcher = fillInPattern.matcher(dataPattern)
                 while (matcher.find()) {
-                    val argName = matcher.group(1)
-                    require(args.containsKey(argName)) {
-                        "Could not find $argName in $args to fill data pattern $dataPattern"
+                    args.read {
+                        val argName = matcher.group(1)!!
+                        require(contains(argName)) {
+                            "Could not find $argName in $args to fill data pattern $dataPattern"
+                        }
+                        matcher.appendReplacement(data, "")
+                        // Serialize with NavType if present, otherwise fallback to toString()
+                        val navType = destination.arguments[argName]?.type
+                        val value =
+                            navType?.serializeAsValue(navType[args, argName])
+                                ?: Uri.encode(args.get(argName).toString())
+                        data.append(value)
                     }
-                    matcher.appendReplacement(data, "")
-                    // Serialize with NavType if present, otherwise fallback to toString()
-                    val navType = destination.arguments[argName!!]?.type
-                    val value =
-                        navType?.serializeAsValue(navType[args, argName])
-                            ?: Uri.encode(args[argName].toString())
-                    data.append(value)
                 }
                 matcher.appendTail(data)
                 intent.data = Uri.parse(data.toString())
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
similarity index 97%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
index 8fdb188..9be7470 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorDestinationBuilder.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorDestinationBuilder.android.kt
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-@file:Suppress("NOTHING_TO_INLINE")
+@file:JvmName("ActivityNavigatorDestinationBuilderKt")
+@file:JvmMultifileClass
 
 package androidx.navigation
 
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
index f280a1a..1611117 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/ActivityNavigatorExtras.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/ActivityNavigatorExtras.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ActivityNavigatorExtrasKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import androidx.core.app.ActivityOptionsCompat
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavBackStackEntryState.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavBackStackEntryState.android.kt
index 2fec191..be20880 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavBackStackEntryState.android.kt
@@ -17,23 +17,23 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.os.Bundle
 import android.os.Parcel
 import android.os.Parcelable
 import androidx.lifecycle.Lifecycle
+import androidx.savedstate.SavedState
 
 @SuppressLint("BanParcelableUsage")
 internal class NavBackStackEntryState : Parcelable {
     val id: String
     val destinationId: Int
-    val args: Bundle?
-    val savedState: Bundle
+    val args: SavedState?
+    val savedState: SavedState
 
     constructor(entry: NavBackStackEntry) {
         id = entry.id
         destinationId = entry.destination.id
         args = entry.arguments
-        savedState = Bundle()
+        savedState = SavedState()
         entry.saveState(savedState)
     }
 
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
similarity index 93%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
index d592f33..145193d 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavController.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("NavControllerKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.app.Activity
@@ -21,7 +24,6 @@
 import android.content.ContextWrapper
 import android.content.Intent
 import android.net.Uri
-import android.os.Bundle
 import android.os.Parcelable
 import android.util.Log
 import androidx.activity.OnBackPressedCallback
@@ -33,7 +35,6 @@
 import androidx.annotation.RestrictTo
 import androidx.core.app.TaskStackBuilder
 import androidx.core.net.toUri
-import androidx.core.os.bundleOf
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleEventObserver
 import androidx.lifecycle.LifecycleObserver
@@ -46,6 +47,10 @@
 import androidx.navigation.NavGraph.Companion.findStartDestination
 import androidx.navigation.serialization.generateHashCode
 import androidx.navigation.serialization.generateRouteWithArgs
+import androidx.savedstate.SavedState
+import androidx.savedstate.read
+import androidx.savedstate.savedState
+import androidx.savedstate.write
 import java.util.concurrent.CopyOnWriteArrayList
 import java.util.concurrent.atomic.AtomicInteger
 import kotlin.collections.removeFirst as removeFirstKt
@@ -109,7 +114,7 @@
             setGraph(graph, null)
         }
 
-    private var navigatorStateToRestore: Bundle? = null
+    private var navigatorStateToRestore: SavedState? = null
     private var backStackToRestore: Array<Parcelable>? = null
     private var deepLinkHandled = false
 
@@ -239,7 +244,7 @@
         public fun onDestinationChanged(
             controller: NavController,
             destination: NavDestination,
-            arguments: Bundle?
+            arguments: SavedState?
         )
     }
 
@@ -333,7 +338,7 @@
             super.push(backStackEntry)
         }
 
-        override fun createBackStackEntry(destination: NavDestination, arguments: Bundle?) =
+        override fun createBackStackEntry(destination: NavDestination, arguments: SavedState?) =
             NavBackStackEntry.create(context, destination, arguments, hostLifecycleState, viewModel)
 
         override fun pop(popUpTo: NavBackStackEntry, saveState: Boolean) {
@@ -1005,7 +1010,7 @@
         val extras = intent.extras
 
         val deepLinkIds = extras!!.getIntArray(KEY_DEEP_LINK_IDS)!!.toMutableList()
-        val deepLinkArgs = extras.getParcelableArrayList<Bundle>(KEY_DEEP_LINK_ARGS)
+        val deepLinkArgs = extras.getParcelableArrayList<SavedState>(KEY_DEEP_LINK_ARGS)
 
         // Remove the leaf destination to pop up to one level above it
         var leafDestinationId = deepLinkIds.removeLastKt()
@@ -1031,8 +1036,10 @@
         val navDeepLinkBuilder = createDeepLink()
 
         // Attach the original global arguments, and also the original calling Intent.
-        val arguments = bundleOf(KEY_DEEP_LINK_INTENT to intent)
-        extras.getBundle(KEY_DEEP_LINK_EXTRAS)?.let { arguments.putAll(it) }
+        val arguments = savedState {
+            putParcelable(KEY_DEEP_LINK_INTENT, intent)
+            extras.getBundle(KEY_DEEP_LINK_EXTRAS)?.let { putAll(it) }
+        }
         navDeepLinkBuilder.setArguments(arguments)
 
         deepLinkIds.forEachIndexed { index, deepLinkId ->
@@ -1054,29 +1061,30 @@
         var parent = currentDestination.parent
         while (parent != null) {
             if (parent.startDestinationId != destId) {
-                val args = Bundle()
-                if (activity != null && activity!!.intent != null) {
-                    val data = activity!!.intent.data
+                val args = savedState {
+                    if (activity != null && activity!!.intent != null) {
+                        val data = activity!!.intent.data
 
-                    // We were started via a URI intent.
-                    if (data != null) {
-                        // Include the original deep link Intent so the Destinations can
-                        // synthetically generate additional arguments as necessary.
-                        args.putParcelable(KEY_DEEP_LINK_INTENT, activity!!.intent)
-                        val currGraph = backQueue.getTopGraph()
-                        val matchingDeepLink =
-                            currGraph.matchDeepLinkComprehensive(
-                                navDeepLinkRequest = NavDeepLinkRequest(activity!!.intent),
-                                searchChildren = true,
-                                searchParent = true,
-                                lastVisited = currGraph
-                            )
-                        if (matchingDeepLink?.matchingArgs != null) {
-                            val destinationArgs =
-                                matchingDeepLink.destination.addInDefaultArgs(
-                                    matchingDeepLink.matchingArgs
+                        // We were started via a URI intent.
+                        if (data != null) {
+                            // Include the original deep link Intent so the Destinations can
+                            // synthetically generate additional arguments as necessary.
+                            putParcelable(KEY_DEEP_LINK_INTENT, activity!!.intent)
+                            val currGraph = backQueue.getTopGraph()
+                            val matchingDeepLink =
+                                currGraph.matchDeepLinkComprehensive(
+                                    navDeepLinkRequest = NavDeepLinkRequest(activity!!.intent),
+                                    searchChildren = true,
+                                    searchParent = true,
+                                    lastVisited = currGraph
                                 )
-                            args.putAll(destinationArgs)
+                            if (matchingDeepLink?.matchingArgs != null) {
+                                val destinationArgs =
+                                    matchingDeepLink.destination.addInDefaultArgs(
+                                        matchingDeepLink.matchingArgs
+                                    )
+                                destinationArgs?.let { putAll(it) }
+                            }
                         }
                     }
                 }
@@ -1349,7 +1357,7 @@
      */
     @MainThread
     @CallSuper
-    public open fun setGraph(@NavigationRes graphResId: Int, startDestinationArgs: Bundle?) {
+    public open fun setGraph(@NavigationRes graphResId: Int, startDestinationArgs: SavedState?) {
         setGraph(navInflater.inflate(graphResId), startDestinationArgs)
     }
 
@@ -1366,7 +1374,7 @@
      */
     @MainThread
     @CallSuper
-    public open fun setGraph(graph: NavGraph, startDestinationArgs: Bundle?) {
+    public open fun setGraph(graph: NavGraph, startDestinationArgs: SavedState?) {
         check(backQueue.isEmpty() || hostLifecycleState != Lifecycle.State.DESTROYED) {
             "You cannot set a new graph on a NavController with entries on the back stack " +
                 "after the NavController has been destroyed. Please ensure that your NavHost " +
@@ -1413,16 +1421,15 @@
     }
 
     @MainThread
-    private fun onGraphCreated(startDestinationArgs: Bundle?) {
-        navigatorStateToRestore?.let { navigatorStateToRestore ->
-            val navigatorNames =
-                navigatorStateToRestore.getStringArrayList(KEY_NAVIGATOR_STATE_NAMES)
-            if (navigatorNames != null) {
+    private fun onGraphCreated(startDestinationArgs: SavedState?) {
+        navigatorStateToRestore?.read {
+            if (contains(KEY_NAVIGATOR_STATE_NAMES)) {
+                val navigatorNames = getStringList(KEY_NAVIGATOR_STATE_NAMES)
                 for (name in navigatorNames) {
                     val navigator = _navigatorProvider.getNavigator<Navigator<*>>(name)
-                    val bundle = navigatorStateToRestore.getBundle(name)
-                    if (bundle != null) {
-                        navigator.onRestoreState(bundle)
+                    if (contains(name)) {
+                        val savedState = getSavedState(name)
+                        navigator.onRestoreState(savedState)
                     }
                 }
             }
@@ -1508,11 +1515,11 @@
                 Log.e(TAG, "handleDeepLink() could not extract deepLink from $intent", e)
                 null
             }
-        var deepLinkArgs = extras?.getParcelableArrayList<Bundle>(KEY_DEEP_LINK_ARGS)
-        val globalArgs = Bundle()
+        var deepLinkArgs = extras?.getParcelableArrayList<SavedState>(KEY_DEEP_LINK_ARGS)
+        val globalArgs = savedState()
         val deepLinkExtras = extras?.getBundle(KEY_DEEP_LINK_EXTRAS)
         if (deepLinkExtras != null) {
-            globalArgs.putAll(deepLinkExtras)
+            globalArgs.write { putAll(deepLinkExtras) }
         }
         if (deepLink == null || deepLink.isEmpty()) {
             val currGraph = backQueue.getTopGraph()
@@ -1529,7 +1536,7 @@
                 deepLinkArgs = null
                 val destinationArgs = destination.addInDefaultArgs(matchingDeepLink.matchingArgs)
                 if (destinationArgs != null) {
-                    globalArgs.putAll(destinationArgs)
+                    globalArgs.write { putAll(destinationArgs) }
                 }
             }
         }
@@ -1545,15 +1552,16 @@
             )
             return false
         }
-        globalArgs.putParcelable(KEY_DEEP_LINK_INTENT, intent)
-        val args = arrayOfNulls<Bundle>(deepLink.size)
+        globalArgs.write { putParcelable(KEY_DEEP_LINK_INTENT, intent) }
+        val args = arrayOfNulls<SavedState>(deepLink.size)
         for (index in args.indices) {
-            val arguments = Bundle()
-            arguments.putAll(globalArgs)
-            if (deepLinkArgs != null) {
-                val deepLinkArguments = deepLinkArgs[index]
-                if (deepLinkArguments != null) {
-                    arguments.putAll(deepLinkArguments)
+            val arguments = savedState {
+                putAll(globalArgs)
+                if (deepLinkArgs != null) {
+                    val deepLinkArguments = deepLinkArgs[index]
+                    if (deepLinkArguments != null) {
+                        putAll(deepLinkArguments)
+                    }
                 }
             }
             args[index] = arguments
@@ -1604,15 +1612,15 @@
         if (matchingDeepLink != null) {
             val destination = matchingDeepLink.destination
             val deepLink = destination.buildDeepLinkIds()
-            val globalArgs = Bundle()
-            val destinationArgs = destination.addInDefaultArgs(matchingDeepLink.matchingArgs)
-            if (destinationArgs != null) {
-                globalArgs.putAll(destinationArgs)
+            val globalArgs = savedState {
+                val destinationArgs = destination.addInDefaultArgs(matchingDeepLink.matchingArgs)
+                if (destinationArgs != null) {
+                    putAll(destinationArgs)
+                }
             }
-            val args = arrayOfNulls<Bundle>(deepLink.size)
+            val args = arrayOfNulls<SavedState>(deepLink.size)
             for (index in args.indices) {
-                val arguments = Bundle()
-                arguments.putAll(globalArgs)
+                val arguments = savedState { putAll(globalArgs) }
                 args[index] = arguments
             }
             return handleDeepLink(deepLink, args, true)
@@ -1622,7 +1630,7 @@
 
     private fun handleDeepLink(
         deepLink: IntArray,
-        args: Array<Bundle?>,
+        args: Array<SavedState?>,
         newTask: Boolean
     ): Boolean {
         if (newTask) {
@@ -1883,7 +1891,7 @@
      *   destination
      */
     @MainThread
-    public open fun navigate(@IdRes resId: Int, args: Bundle?) {
+    public open fun navigate(@IdRes resId: Int, args: SavedState?) {
         navigate(resId, args, null)
     }
 
@@ -1902,7 +1910,7 @@
      *   destination
      */
     @MainThread
-    public open fun navigate(@IdRes resId: Int, args: Bundle?, navOptions: NavOptions?) {
+    public open fun navigate(@IdRes resId: Int, args: SavedState?, navOptions: NavOptions?) {
         navigate(resId, args, navOptions, null)
     }
 
@@ -1925,7 +1933,7 @@
     @MainThread
     public open fun navigate(
         @IdRes resId: Int,
-        args: Bundle?,
+        args: SavedState?,
         navOptions: NavOptions?,
         navigatorExtras: Navigator.Extras?
     ) {
@@ -1939,7 +1947,7 @@
 
         @IdRes var destId = resId
         val navAction = currentNode.getAction(resId)
-        var combinedArgs: Bundle? = null
+        var combinedArgs: SavedState? = null
         if (navAction != null) {
             if (finalNavOptions == null) {
                 finalNavOptions = navAction.navOptions
@@ -1947,15 +1955,14 @@
             destId = navAction.destinationId
             val navActionArgs = navAction.defaultArguments
             if (navActionArgs != null) {
-                combinedArgs = Bundle()
-                combinedArgs.putAll(navActionArgs)
+                combinedArgs = savedState { putAll(navActionArgs) }
             }
         }
         if (args != null) {
             if (combinedArgs == null) {
-                combinedArgs = Bundle()
+                combinedArgs = savedState()
             }
-            combinedArgs.putAll(args)
+            combinedArgs.write { putAll(args) }
         }
         // just pop and return if destId is invalid
         if (
@@ -2109,14 +2116,14 @@
             )
         if (deepLinkMatch != null) {
             val destination = deepLinkMatch.destination
-            val args = destination.addInDefaultArgs(deepLinkMatch.matchingArgs) ?: Bundle()
+            val args = destination.addInDefaultArgs(deepLinkMatch.matchingArgs) ?: savedState()
             val node = deepLinkMatch.destination
             val intent =
                 Intent().apply {
                     setDataAndType(request.uri, request.mimeType)
                     action = request.action
                 }
-            args.putParcelable(KEY_DEEP_LINK_INTENT, intent)
+            args.write { putParcelable(KEY_DEEP_LINK_INTENT, intent) }
             navigate(node, args, navOptions, navigatorExtras)
         } else {
             throw IllegalArgumentException(
@@ -2130,7 +2137,7 @@
     @MainThread
     private fun navigate(
         node: NavDestination,
-        args: Bundle?,
+        args: SavedState?,
         navOptions: NavOptions?,
         navigatorExtras: Navigator.Extras?
     ) {
@@ -2205,7 +2212,7 @@
         }
     }
 
-    private fun launchSingleTopInternal(node: NavDestination, args: Bundle?): Boolean {
+    private fun launchSingleTopInternal(node: NavDestination, args: SavedState?): Boolean {
         val currentBackStackEntry = currentBackStackEntry
         val nodeIndex = backQueue.indexOfLast { it.destination === node }
         // early return when node isn't even in backQueue
@@ -2254,7 +2261,7 @@
 
     private fun restoreStateInternal(
         id: Int,
-        args: Bundle?,
+        args: SavedState?,
         navOptions: NavOptions?,
         navigatorExtras: Navigator.Extras?
     ): Boolean {
@@ -2303,7 +2310,7 @@
 
     private fun executeRestoreState(
         entries: List<NavBackStackEntry>,
-        args: Bundle?,
+        args: SavedState?,
         navOptions: NavOptions?,
         navigatorExtras: Navigator.Extras?
     ): Boolean {
@@ -2373,7 +2380,7 @@
 
     private fun addEntryToBackStack(
         node: NavDestination,
-        finalArgs: Bundle?,
+        finalArgs: SavedState?,
         backStackEntry: NavBackStackEntry,
         restoredEntries: List<NavBackStackEntry> = emptyList()
     ) {
@@ -2430,7 +2437,7 @@
         ) {
             val parent = destination.parent
             if (parent != null) {
-                val args = if (finalArgs?.isEmpty == true) null else finalArgs
+                val args = if (finalArgs?.read { isEmpty() } == true) null else finalArgs
                 val entry =
                     restoredEntries.lastOrNull { restoredEntry ->
                         restoredEntry.destination == parent
@@ -2580,14 +2587,14 @@
             )
         if (deepLinkMatch != null) {
             val destination = deepLinkMatch.destination
-            val args = destination.addInDefaultArgs(deepLinkMatch.matchingArgs) ?: Bundle()
+            val args = destination.addInDefaultArgs(deepLinkMatch.matchingArgs) ?: savedState()
             val node = deepLinkMatch.destination
             val intent =
                 Intent().apply {
                     setDataAndType(createRoute(destination.route).toUri(), null)
                     action = null
                 }
-            args.putParcelable(KEY_DEEP_LINK_INTENT, intent)
+            args.write { putParcelable(KEY_DEEP_LINK_INTENT, intent) }
             navigate(node, args, navOptions, navigatorExtras)
         } else {
             throw IllegalArgumentException(
@@ -2649,44 +2656,45 @@
     }
 
     /**
-     * Saves all navigation controller state to a Bundle.
+     * Saves all navigation controller state to a SavedState.
      *
-     * State may be restored from a bundle returned from this method by calling [restoreState].
+     * State may be restored from a SavedState returned from this method by calling [restoreState].
      * Saving controller state is the responsibility of a [NavHost].
      *
      * @return saved state for this controller
      */
     @CallSuper
-    public open fun saveState(): Bundle? {
-        var b: Bundle? = null
+    public open fun saveState(): SavedState? {
+        var b: SavedState? = null
         val navigatorNames = ArrayList<String>()
-        val navigatorState = Bundle()
+        val navigatorState = savedState()
         for ((name, value) in _navigatorProvider.navigators) {
             val savedState = value.onSaveState()
             if (savedState != null) {
                 navigatorNames.add(name)
-                navigatorState.putBundle(name, savedState)
+                navigatorState.write { putSavedState(name, savedState) }
             }
         }
         if (navigatorNames.isNotEmpty()) {
-            b = Bundle()
-            navigatorState.putStringArrayList(KEY_NAVIGATOR_STATE_NAMES, navigatorNames)
-            b.putBundle(KEY_NAVIGATOR_STATE, navigatorState)
+            b = savedState {
+                navigatorState.write { putStringList(KEY_NAVIGATOR_STATE_NAMES, navigatorNames) }
+                putSavedState(KEY_NAVIGATOR_STATE, navigatorState)
+            }
         }
         if (backQueue.isNotEmpty()) {
             if (b == null) {
-                b = Bundle()
+                b = savedState()
             }
             val backStack = arrayOfNulls<Parcelable>(backQueue.size)
             var index = 0
             for (backStackEntry in this.backQueue) {
                 backStack[index++] = NavBackStackEntryState(backStackEntry)
             }
-            b.putParcelableArray(KEY_BACK_STACK, backStack)
+            b.write { putParcelableList(KEY_BACK_STACK, backStack.toList().filterNotNull()) }
         }
         if (backStackMap.isNotEmpty()) {
             if (b == null) {
-                b = Bundle()
+                b = savedState()
             }
             val backStackDestIds = IntArray(backStackMap.size)
             val backStackIds = ArrayList<String?>()
@@ -2695,12 +2703,14 @@
                 backStackDestIds[index++] = destId
                 backStackIds += id
             }
-            b.putIntArray(KEY_BACK_STACK_DEST_IDS, backStackDestIds)
-            b.putStringArrayList(KEY_BACK_STACK_IDS, backStackIds)
+            b.write {
+                putIntArray(KEY_BACK_STACK_DEST_IDS, backStackDestIds)
+                putStringList(KEY_BACK_STACK_IDS, backStackIds.toList().filterNotNull())
+            }
         }
         if (backStackStates.isNotEmpty()) {
             if (b == null) {
-                b = Bundle()
+                b = savedState()
             }
             val backStackStateIds = ArrayList<String>()
             for ((id, backStackStates) in backStackStates) {
@@ -2709,56 +2719,73 @@
                 backStackStates.forEachIndexed { stateIndex, backStackState ->
                     states[stateIndex] = backStackState
                 }
-                b.putParcelableArray(KEY_BACK_STACK_STATES_PREFIX + id, states)
+                b.write {
+                    putParcelableList(
+                        KEY_BACK_STACK_STATES_PREFIX + id,
+                        states.toList().filterNotNull()
+                    )
+                }
             }
-            b.putStringArrayList(KEY_BACK_STACK_STATES_IDS, backStackStateIds)
+            b.write { putStringList(KEY_BACK_STACK_STATES_IDS, backStackStateIds) }
         }
         if (deepLinkHandled) {
             if (b == null) {
-                b = Bundle()
+                b = savedState()
             }
-            b.putBoolean(KEY_DEEP_LINK_HANDLED, deepLinkHandled)
+            b.write { putBoolean(KEY_DEEP_LINK_HANDLED, deepLinkHandled) }
         }
         return b
     }
 
     /**
-     * Restores all navigation controller state from a bundle. This should be called before any call
-     * to [setGraph].
+     * Restores all navigation controller state from a SavedState. This should be called before any
+     * call to [setGraph].
      *
-     * State may be saved to a bundle by calling [saveState]. Restoring controller state is the
+     * State may be saved to a SavedState by calling [saveState]. Restoring controller state is the
      * responsibility of a [NavHost].
      *
-     * @param navState state bundle to restore
+     * @param navState SavedState to restore
      */
     @CallSuper
-    @Suppress("DEPRECATION")
-    public open fun restoreState(navState: Bundle?) {
+    public open fun restoreState(navState: SavedState?) {
         if (navState == null) {
             return
         }
         navState.classLoader = context.classLoader
-        navigatorStateToRestore = navState.getBundle(KEY_NAVIGATOR_STATE)
-        backStackToRestore = navState.getParcelableArray(KEY_BACK_STACK)
-        backStackStates.clear()
-        val backStackDestIds = navState.getIntArray(KEY_BACK_STACK_DEST_IDS)
-        val backStackIds = navState.getStringArrayList(KEY_BACK_STACK_IDS)
-        if (backStackDestIds != null && backStackIds != null) {
-            backStackDestIds.forEachIndexed { index, id -> backStackMap[id] = backStackIds[index] }
-        }
-        val backStackStateIds = navState.getStringArrayList(KEY_BACK_STACK_STATES_IDS)
-        backStackStateIds?.forEach { id ->
-            val backStackState = navState.getParcelableArray(KEY_BACK_STACK_STATES_PREFIX + id)
-            if (backStackState != null) {
-                backStackStates[id] =
-                    ArrayDeque<NavBackStackEntryState>(backStackState.size).apply {
-                        for (parcelable in backStackState) {
-                            add(parcelable as NavBackStackEntryState)
-                        }
-                    }
+        navState.read {
+            navigatorStateToRestore =
+                if (contains(KEY_NAVIGATOR_STATE)) {
+                    getSavedState(KEY_NAVIGATOR_STATE)
+                } else null
+            backStackToRestore =
+                if (contains(KEY_BACK_STACK)) {
+                    getParcelableList<Parcelable>(KEY_BACK_STACK).toTypedArray()
+                } else null
+            backStackStates.clear()
+            if (contains(KEY_BACK_STACK_DEST_IDS) && contains(KEY_BACK_STACK_IDS)) {
+                val backStackDestIds = getIntArray(KEY_BACK_STACK_DEST_IDS)
+                val backStackIds = getStringArray(KEY_BACK_STACK_IDS)
+                backStackDestIds.forEachIndexed { index, id ->
+                    backStackMap[id] = backStackIds[index]
+                }
             }
+            if (contains(KEY_BACK_STACK_STATES_IDS)) {
+                val backStackStateIds = getStringArray(KEY_BACK_STACK_STATES_IDS)
+                backStackStateIds.forEach { id ->
+                    if (contains(KEY_BACK_STACK_STATES_PREFIX + id)) {
+                        val backStackState =
+                            getParcelableList<Parcelable>(KEY_BACK_STACK_STATES_PREFIX + id)
+                        backStackStates[id] =
+                            ArrayDeque<NavBackStackEntryState>(backStackState.size).apply {
+                                for (parcelable in backStackState) {
+                                    add(parcelable as NavBackStackEntryState)
+                                }
+                            }
+                    }
+                }
+            }
+            deepLinkHandled = getBooleanOrElse(KEY_DEEP_LINK_HANDLED) { false }
         }
-        deepLinkHandled = navState.getBoolean(KEY_DEEP_LINK_HANDLED)
     }
 
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavControllerViewModel.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavControllerViewModel.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavControllerViewModel.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavControllerViewModel.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkBuilder.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavDeepLinkBuilder.android.kt
similarity index 91%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkBuilder.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavDeepLinkBuilder.android.kt
index 3e65714..649ba64 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkBuilder.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavDeepLinkBuilder.android.kt
@@ -21,11 +21,12 @@
 import android.content.Context
 import android.content.ContextWrapper
 import android.content.Intent
-import android.os.Bundle
 import androidx.annotation.IdRes
 import androidx.annotation.NavigationRes
 import androidx.core.app.TaskStackBuilder
 import androidx.navigation.NavDestination.Companion.createRoute
+import androidx.savedstate.SavedState
+import androidx.savedstate.read
 
 /**
  * Class used to construct deep links to a particular destination in a [NavGraph].
@@ -50,7 +51,8 @@
  * @see NavDeepLinkBuilder.setComponentName
  */
 public class NavDeepLinkBuilder(private val context: Context) {
-    private class DeepLinkDestination constructor(val destinationId: Int, val arguments: Bundle?)
+    private class DeepLinkDestination
+    constructor(val destinationId: Int, val arguments: SavedState?)
 
     private val activity: Activity? =
         generateSequence(context) { (it as? ContextWrapper)?.baseContext }
@@ -67,7 +69,7 @@
             .also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) }
     private var graph: NavGraph? = null
     private val destinations = mutableListOf<DeepLinkDestination>()
-    private var globalArgs: Bundle? = null
+    private var globalArgs: SavedState? = null
 
     /** @see NavController.createDeepLink */
     internal constructor(navController: NavController) : this(navController.context) {
@@ -132,7 +134,7 @@
      * @return this object for chaining
      */
     @JvmOverloads
-    public fun setDestination(@IdRes destId: Int, args: Bundle? = null): NavDeepLinkBuilder {
+    public fun setDestination(@IdRes destId: Int, args: SavedState? = null): NavDeepLinkBuilder {
         destinations.clear()
         destinations.add(DeepLinkDestination(destId, args))
         if (graph != null) {
@@ -152,7 +154,7 @@
      * @return this object for chaining
      */
     @JvmOverloads
-    public fun setDestination(destRoute: String, args: Bundle? = null): NavDeepLinkBuilder {
+    public fun setDestination(destRoute: String, args: SavedState? = null): NavDeepLinkBuilder {
         destinations.clear()
         destinations.add(DeepLinkDestination(createRoute(destRoute).hashCode(), args))
         if (graph != null) {
@@ -190,7 +192,7 @@
      * @return this object for chaining
      */
     @JvmOverloads
-    public fun addDestination(@IdRes destId: Int, args: Bundle? = null): NavDeepLinkBuilder {
+    public fun addDestination(@IdRes destId: Int, args: SavedState? = null): NavDeepLinkBuilder {
         destinations.add(DeepLinkDestination(destId, args))
         if (graph != null) {
             verifyAllDestinations()
@@ -210,7 +212,7 @@
      * @return this object for chaining
      */
     @JvmOverloads
-    public fun addDestination(route: String, args: Bundle? = null): NavDeepLinkBuilder {
+    public fun addDestination(route: String, args: SavedState? = null): NavDeepLinkBuilder {
         destinations.add(DeepLinkDestination(createRoute(route).hashCode(), args))
         if (graph != null) {
             verifyAllDestinations()
@@ -249,7 +251,7 @@
 
     private fun fillInIntent() {
         val deepLinkIds = mutableListOf<Int>()
-        val deepLinkArgs = ArrayList<Bundle?>()
+        val deepLinkArgs = ArrayList<SavedState?>()
         var previousDestination: NavDestination? = null
         for (destination in destinations) {
             val destId = destination.destinationId
@@ -278,7 +280,7 @@
      * @param args arguments to pass to each destination
      * @return this object for chaining
      */
-    public fun setArguments(args: Bundle?): NavDeepLinkBuilder {
+    public fun setArguments(args: SavedState?): NavDeepLinkBuilder {
         globalArgs = args
         intent.putExtra(NavController.KEY_DEEP_LINK_EXTRAS, args)
         return this
@@ -330,22 +332,13 @@
      */
     @Suppress("DEPRECATION")
     public fun createPendingIntent(): PendingIntent {
-        var requestCode = 0
-        globalArgs?.let { globalArgs ->
-            for (key in globalArgs.keySet()) {
-                val value = globalArgs[key]
-                requestCode = 31 * requestCode + (value?.hashCode() ?: 0)
-            }
-        }
+        var requestCode = globalArgs?.read { contentDeepHashCode() } ?: 0
         for (destination in destinations) {
             val destId = destination.destinationId
             requestCode = 31 * requestCode + destId
-            val arguments = destination.arguments
-            if (arguments != null) {
-                for (key in arguments.keySet()) {
-                    val value = arguments[key]
-                    requestCode = 31 * requestCode + (value?.hashCode() ?: 0)
-                }
+            val argumentsHashCode = destination.arguments?.read { contentDeepHashCode() }
+            if (argumentsHashCode != null) {
+                requestCode = 31 * requestCode + argumentsHashCode
             }
         }
         return createTaskStackBuilder()
@@ -369,7 +362,7 @@
 
                 override fun navigate(
                     destination: NavDestination,
-                    args: Bundle?,
+                    args: SavedState?,
                     navOptions: NavOptions?,
                     navigatorExtras: Extras?
                 ): NavDestination? {
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
similarity index 98%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
index 30024a2..b21b710 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHost.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHost.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("NavHostKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import androidx.annotation.IdRes
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavHostController.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHostController.android.kt
similarity index 100%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavHostController.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavHostController.android.kt
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavInflater.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavInflater.android.kt
similarity index 97%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavInflater.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavInflater.android.kt
index f8e46da..a3e0c58 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavInflater.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/NavInflater.android.kt
@@ -20,7 +20,6 @@
 import android.content.res.Resources
 import android.content.res.TypedArray
 import android.content.res.XmlResourceParser
-import android.os.Bundle
 import android.util.AttributeSet
 import android.util.TypedValue
 import android.util.Xml
@@ -29,6 +28,9 @@
 import androidx.core.content.res.use
 import androidx.core.content.withStyledAttributes
 import androidx.navigation.common.R
+import androidx.savedstate.SavedState
+import androidx.savedstate.read
+import androidx.savedstate.savedState
 import java.io.IOException
 import org.xmlpull.v1.XmlPullParser
 import org.xmlpull.v1.XmlPullParserException
@@ -137,7 +139,7 @@
     @Throws(XmlPullParserException::class)
     private fun inflateArgumentForBundle(
         res: Resources,
-        bundle: Bundle,
+        savedState: SavedState,
         attrs: AttributeSet,
         graphResId: Int
     ) {
@@ -147,7 +149,7 @@
                     ?: throw XmlPullParserException("Arguments must have a name")
             val argument = inflateArgument(array, res, graphResId)
             if (argument.isDefaultValuePresent) {
-                argument.putDefaultValue(name, bundle)
+                argument.putDefaultValue(name, savedState)
             }
         }
     }
@@ -309,7 +311,7 @@
             builder.setPopEnterAnim(getResourceId(R.styleable.NavAction_popEnterAnim, -1))
             builder.setPopExitAnim(getResourceId(R.styleable.NavAction_popExitAnim, -1))
             action.navOptions = builder.build()
-            val args = Bundle()
+            val args = savedState()
             val innerDepth = parser.depth + 1
             var type: Int
             var depth = 0
@@ -329,7 +331,7 @@
                     inflateArgumentForBundle(res, args, attrs, graphResId)
                 }
             }
-            if (!args.isEmpty) {
+            if (!args.read { isEmpty() }) {
                 action.defaultArguments = args
             }
             dest.putAction(id, action)
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/Navigation.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Navigation.android.kt
similarity index 98%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/Navigation.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Navigation.android.kt
index 4597770..4cf9a03 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/Navigation.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/Navigation.android.kt
@@ -16,10 +16,10 @@
 package androidx.navigation
 
 import android.app.Activity
-import android.os.Bundle
 import android.view.View
 import androidx.annotation.IdRes
 import androidx.core.app.ActivityCompat
+import androidx.savedstate.SavedState
 import java.lang.ref.WeakReference
 
 /**
@@ -83,7 +83,7 @@
     @JvmOverloads
     public fun createNavigateOnClickListener(
         @IdRes resId: Int,
-        args: Bundle? = null
+        args: SavedState? = null
     ): View.OnClickListener {
         return View.OnClickListener { view -> findNavController(view).navigate(resId, args) }
     }
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt
rename to navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
index 55db610..c5db4bc 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/View.kt
+++ b/navigation/navigation-runtime/src/androidMain/kotlin/androidx/navigation/View.android.kt
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+@file:JvmName("ViewKt")
+@file:JvmMultifileClass
+
 package androidx.navigation
 
 import android.view.View
diff --git a/navigation/navigation-runtime/src/main/res-public/values/public_attrs.xml b/navigation/navigation-runtime/src/androidMain/res-public/values/public_attrs.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res-public/values/public_attrs.xml
rename to navigation/navigation-runtime/src/androidMain/res-public/values/public_attrs.xml
diff --git a/navigation/navigation-runtime/src/main/res/values/attrs.xml b/navigation/navigation-runtime/src/androidMain/res/values/attrs.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res/values/attrs.xml
rename to navigation/navigation-runtime/src/androidMain/res/values/attrs.xml
diff --git a/navigation/navigation-runtime/src/main/res/values/ids.xml b/navigation/navigation-runtime/src/androidMain/res/values/ids.xml
similarity index 100%
rename from navigation/navigation-runtime/src/main/res/values/ids.xml
rename to navigation/navigation-runtime/src/androidMain/res/values/ids.xml
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt b/navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
similarity index 94%
rename from navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
rename to navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
index 469b038..5e7015f 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavDeepLinkSaveStateControl.kt
+++ b/navigation/navigation-runtime/src/commonMain/kotlin/androidx/navigation/NavDeepLinkSaveStateControl.kt
@@ -16,7 +16,6 @@
 
 package androidx.navigation
 
-/** @see NavController.enableDeepLinkSaveState */
 @Retention(AnnotationRetention.BINARY)
 @Target(AnnotationTarget.FUNCTION)
 @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
diff --git a/navigation3/navigation3/api/current.txt b/navigation3/navigation3/api/current.txt
index d8d07e0..36708c9 100644
--- a/navigation3/navigation3/api/current.txt
+++ b/navigation3/navigation3/api/current.txt
@@ -46,20 +46,20 @@
   }
 
   public final class NavDisplay {
-    method public java.util.Map<java.lang.String,java.lang.Object> isDialog(boolean boolean);
+    method public java.util.Map<java.lang.String,java.lang.Object> popTransition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     method public java.util.Map<java.lang.String,java.lang.Object> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     field public static final androidx.navigation3.NavDisplay INSTANCE;
   }
 
   public final class NavDisplay_androidKt {
-    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
+    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.EnterTransition popEnterTransition, optional androidx.compose.animation.ExitTransition popExitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
   }
 
-  public final class NavEntry<T> {
+  public class NavEntry<T> {
     ctor public NavEntry(T key, optional java.util.Map<java.lang.String,?> featureMap, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
-    method public kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
-    method public java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
-    method public T getKey();
+    method public final kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
+    method public final java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
+    method public final T getKey();
     property public final kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
     property public final java.util.Map<java.lang.String,java.lang.Object> featureMap;
     property public final T key;
diff --git a/navigation3/navigation3/api/restricted_current.txt b/navigation3/navigation3/api/restricted_current.txt
index d8d07e0..36708c9 100644
--- a/navigation3/navigation3/api/restricted_current.txt
+++ b/navigation3/navigation3/api/restricted_current.txt
@@ -46,20 +46,20 @@
   }
 
   public final class NavDisplay {
-    method public java.util.Map<java.lang.String,java.lang.Object> isDialog(boolean boolean);
+    method public java.util.Map<java.lang.String,java.lang.Object> popTransition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     method public java.util.Map<java.lang.String,java.lang.Object> transition(androidx.compose.animation.EnterTransition? enter, androidx.compose.animation.ExitTransition? exit);
     field public static final androidx.navigation3.NavDisplay INSTANCE;
   }
 
   public final class NavDisplay_androidKt {
-    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
+    method @androidx.compose.runtime.Composable public static <T> void NavDisplay(java.util.List<? extends T> backstack, optional androidx.compose.ui.Modifier modifier, optional java.util.List<? extends androidx.navigation3.NavLocalProvider> localProviders, optional androidx.compose.ui.Alignment contentAlignment, optional androidx.compose.animation.SizeTransform? sizeTransform, optional androidx.compose.animation.EnterTransition enterTransition, optional androidx.compose.animation.ExitTransition exitTransition, optional androidx.compose.animation.EnterTransition popEnterTransition, optional androidx.compose.animation.ExitTransition popExitTransition, optional kotlin.jvm.functions.Function0<kotlin.Unit> onBack, kotlin.jvm.functions.Function1<? super T,? extends androidx.navigation3.NavEntry<? extends T>> entryProvider);
   }
 
-  public final class NavEntry<T> {
+  public class NavEntry<T> {
     ctor public NavEntry(T key, optional java.util.Map<java.lang.String,?> featureMap, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> content);
-    method public kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
-    method public java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
-    method public T getKey();
+    method public final kotlin.jvm.functions.Function1<T,kotlin.Unit> getContent();
+    method public final java.util.Map<java.lang.String,java.lang.Object> getFeatureMap();
+    method public final T getKey();
     property public final kotlin.jvm.functions.Function1<T,kotlin.Unit> content;
     property public final java.util.Map<java.lang.String,java.lang.Object> featureMap;
     property public final T key;
diff --git a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
index d4728e8..64c39b0 100644
--- a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
+++ b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavDisplaySamples.kt
@@ -21,6 +21,8 @@
 import androidx.compose.animation.slideOutHorizontally
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.lifecycle.viewmodel.navigation3.ViewModelStoreNavLocalProvider
@@ -38,6 +40,7 @@
 @Composable
 fun BaseNav() {
     val backStack = rememberMutableStateListOf(Profile)
+    val showDialog = remember { mutableStateOf(false) }
     NavDisplay(
         backstack = backStack,
         localProviders = listOf(SavedStateNavLocalProvider, ViewModelStoreNavLocalProvider),
@@ -55,8 +58,8 @@
                 ) {
                     Scrollable({ backStack.add(it) }) { backStack.removeLast() }
                 }
-                entry<Dialog>(featureMap = NavDisplay.isDialog(true)) {
-                    DialogContent { backStack.removeLast() }
+                entry<DialogBase> {
+                    DialogBase(onClick = { showDialog.value = true }) { backStack.removeLast() }
                 }
                 entry<Dashboard>(
                     NavDisplay.transition(slideInHorizontally { it }, slideOutHorizontally { it })
@@ -66,4 +69,7 @@
                 }
             }
     )
+    if (showDialog.value) {
+        DialogContent(onDismissRequest = { showDialog.value = false })
+    }
 }
diff --git a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
index 3702017..6a5ec92 100644
--- a/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
+++ b/navigation3/navigation3/samples/src/main/kotlin/androidx/navigation3/samples/NavigationSamples.kt
@@ -42,6 +42,7 @@
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import androidx.compose.ui.window.Dialog
 import androidx.savedstate.serialization.decodeFromSavedState
 import androidx.savedstate.serialization.encodeToSavedState
 import kotlinx.serialization.InternalSerializationApi
@@ -66,7 +67,7 @@
 }
 
 @Serializable
-object Dialog {
+object DialogBase {
     val resourceId: Int = R.string.dialog
 }
 
@@ -85,7 +86,7 @@
         Divider(color = Color.Black)
         NavigateButton(stringResource(Scrollable.resourceId)) { navigateTo(Scrollable) }
         Divider(color = Color.Black)
-        NavigateButton(stringResource(Dialog.resourceId)) { navigateTo(Dialog) }
+        NavigateButton(stringResource(DialogBase.resourceId)) { navigateTo(DialogBase) }
         Spacer(Modifier.weight(1f))
         NavigateBackButton(onBack)
     }
@@ -112,13 +113,24 @@
 }
 
 @Composable
-fun DialogContent(onBack: () -> Unit) {
-    val dialogWidth = 300.dp
-    val dialogHeight = 300.dp
-    Column(Modifier.size(dialogWidth, dialogHeight).background(Color.White).padding(8.dp)) {
+fun DialogBase(onClick: () -> Unit, onBack: () -> Unit) {
+    Column(Modifier.fillMaxSize()) {
+        Text(stringResource(R.string.dialog))
+        Button(onClick = onClick) { Text("Show Dialog") }
+        Spacer(Modifier.weight(1f))
         NavigateBackButton(onBack)
-        LazyColumn(modifier = Modifier.weight(1f)) {
-            items(phrases) { phrase -> Text(phrase, fontSize = 16.sp) }
+    }
+}
+
+@Composable
+fun DialogContent(onDismissRequest: () -> Unit) {
+    Dialog(onDismissRequest = onDismissRequest) {
+        val dialogWidth = 300.dp
+        val dialogHeight = 300.dp
+        Column(Modifier.size(dialogWidth, dialogHeight).background(Color.White).padding(8.dp)) {
+            LazyColumn(modifier = Modifier.weight(1f)) {
+                items(phrases) { phrase -> Text(phrase, fontSize = 16.sp) }
+            }
         }
     }
 }
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
index 6fb5955..be69875 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/AnimatedTest.kt
@@ -138,7 +138,637 @@
         composeTestRule.onNodeWithText(first).assertDoesNotExist()
         composeTestRule.onNodeWithText(second).assertExists()
     }
+
+    @Test
+    fun testPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                            featureMap =
+                                NavDisplay.popTransition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.removeAt(1) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        // pop to first
+        assertThat(backstack).containsExactly(first)
+        composeTestRule.onNodeWithText(first).assertIsDisplayed()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+    }
+
+    @Test
+    fun testPopMultiple() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                            featureMap =
+                                NavDisplay.popTransition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(2)
+            backstack.removeAt(1)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        // pop to first
+        assertThat(backstack).containsExactly(first)
+        composeTestRule.onNodeWithText(first).assertIsDisplayed()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+    }
+
+    @Test
+    fun testPopNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(third)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentrePop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.removeAt(1) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentreNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.add(1, second) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentrePopAndEndPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third, fourth) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third, fourth)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(3)
+            backstack.removeAt(1)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        composeTestRule.onNodeWithText(fourth).assertDoesNotExist()
+    }
+
+    @Test
+    fun testCentrePopAndEndNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(fourth)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, third, fourth)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+    }
+
+    @Test
+    fun testCentreNavigateAndEndPop() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third, fourth) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third, fourth)
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(2)
+            backstack.add(1, second)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        composeTestRule.onNodeWithText(fourth).assertDoesNotExist()
+    }
+
+    @Test
+    fun testCentreNavigateAndEndNavigate() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    fourth ->
+                        NavEntry(
+                            fourth,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(fourth)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.add(1, second)
+            backstack.add(fourth)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third, fourth)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(fourth).assertIsDisplayed()
+    }
+
+    @Test
+    fun testSameStack() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                            NavDisplay.transition(
+                                enter = fadeIn(tween(testDuration)),
+                                exit = fadeOut(tween(testDuration))
+                            )
+                        ) {
+                            Text(second)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle {
+            backstack.removeAt(1)
+            backstack.add(second)
+        }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+    }
+
+    @Test
+    fun testDuplicateLastEntry() {
+        lateinit var backstack: MutableList<Any>
+        val testDuration = DEFAULT_TRANSITION_DURATION_MILLISECOND / 5
+        composeTestRule.setContent {
+            backstack = remember { mutableStateListOf(first, second, third) }
+            NavDisplay(backstack) {
+                when (it) {
+                    first ->
+                        NavEntry(
+                            first,
+                        ) {
+                            Text(first)
+                        }
+                    second ->
+                        NavEntry(
+                            second,
+                            featureMap =
+                                NavDisplay.transition(
+                                    enter = fadeIn(tween(testDuration)),
+                                    exit = fadeOut(tween(testDuration))
+                                )
+                        ) {
+                            Text(second)
+                        }
+                    third ->
+                        NavEntry(
+                            third,
+                        ) {
+                            Text(third)
+                        }
+                    else -> error("Invalid key passed")
+                }
+            }
+        }
+
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertIsDisplayed()
+        assertThat(backstack).containsExactly(first, second, third)
+
+        composeTestRule.mainClock.autoAdvance = false
+        composeTestRule.runOnIdle { backstack.add(second) }
+
+        // advance by a duration that is much shorter than the default duration
+        // to ensure that the custom animation is used and has completed after this
+        composeTestRule.mainClock.advanceTimeBy((testDuration * 1.5).toLong())
+        // not pop
+        composeTestRule.waitForIdle()
+        assertThat(backstack).containsExactly(first, second, third, second)
+        composeTestRule.onNodeWithText(first).assertDoesNotExist()
+        composeTestRule.onNodeWithText(third).assertDoesNotExist()
+        composeTestRule.onNodeWithText(second).assertIsDisplayed()
+    }
 }
 
 private const val first = "first"
 private const val second = "second"
+private const val third = "third"
+private const val fourth = "fourth"
diff --git a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
index 614eb88..3342fbf 100644
--- a/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
+++ b/navigation3/navigation3/src/androidInstrumentedTest/kotlin/androidx/navigation3/NavDisplayTest.kt
@@ -18,6 +18,7 @@
 
 import androidx.activity.OnBackPressedDispatcher
 import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
+import androidx.compose.material3.Button
 import androidx.compose.material3.Text
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateListOf
@@ -28,6 +29,8 @@
 import androidx.compose.ui.test.isDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.window.Dialog
 import androidx.kruth.assertThat
 import androidx.savedstate.SavedStateRegistry
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -78,20 +81,28 @@
     fun testDialog() {
         lateinit var backstack: MutableList<Any>
         composeTestRule.setContent {
+            var showDialog = remember { mutableStateOf(false) }
             backstack = remember { mutableStateListOf(first) }
             NavDisplay(backstack = backstack) {
                 when (it) {
-                    first -> NavEntry(first) { Text(first) }
-                    second -> NavEntry(second, NavDisplay.isDialog(true)) { Text(second) }
+                    first ->
+                        NavEntry(first) {
+                            Button(onClick = { showDialog.value = true }) { Text(first) }
+                        }
                     else -> error("Invalid key passed")
                 }
             }
+            if (showDialog.value) {
+                Dialog(onDismissRequest = {}) { Text(second) }
+            }
         }
 
         assertThat(composeTestRule.onNodeWithText(first).isDisplayed()).isTrue()
 
-        composeTestRule.runOnIdle { backstack.add(second) }
+        composeTestRule.waitForIdle()
+        composeTestRule.onNodeWithText(first).performClick()
 
+        composeTestRule.waitForIdle()
         // Both first and second should be showing if we are on a dialog.
         assertThat(composeTestRule.onNodeWithText(first).isDisplayed()).isTrue()
         assertThat(composeTestRule.onNodeWithText(second).isDisplayed()).isTrue()
diff --git a/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt b/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
index fdc1e24..fbfa0d7 100644
--- a/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
+++ b/navigation3/navigation3/src/androidMain/kotlin/androidx/navigation3/NavDisplay.android.kt
@@ -26,10 +26,14 @@
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.window.Dialog
 import androidx.navigation3.NavDisplay.DEFAULT_TRANSITION_DURATION_MILLISECOND
+import androidx.navigation3.NavDisplay.ENTER_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.EXIT_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.POP_ENTER_TRANSITION_KEY
+import androidx.navigation3.NavDisplay.POP_EXIT_TRANSITION_KEY
 
 /** Object that indicates the features that can be handled by the [NavDisplay] */
 public object NavDisplay {
@@ -42,15 +46,17 @@
         else mapOf(ENTER_TRANSITION_KEY to enter, EXIT_TRANSITION_KEY to exit)
 
     /**
-     * Function to be called on the [NavEntry.featureMap] to notify the [NavDisplay] that the
-     * content should be displayed inside of a [Dialog]
+     * Function to be called on the [NavEntry.featureMap] to notify the [NavDisplay] that, when
+     * popping from backstack, the content should be animated using the provided transitions.
      */
-    public fun isDialog(boolean: Boolean): Map<String, Any> =
-        if (!boolean) emptyMap() else mapOf(DIALOG_KEY to true)
+    public fun popTransition(enter: EnterTransition?, exit: ExitTransition?): Map<String, Any> =
+        if (enter == null || exit == null) emptyMap()
+        else mapOf(POP_ENTER_TRANSITION_KEY to enter, POP_EXIT_TRANSITION_KEY to exit)
 
     internal const val ENTER_TRANSITION_KEY = "enterTransition"
     internal const val EXIT_TRANSITION_KEY = "exitTransition"
-    internal const val DIALOG_KEY = "dialog"
+    internal const val POP_ENTER_TRANSITION_KEY = "popEnterTransition"
+    internal const val POP_EXIT_TRANSITION_KEY = "popExitTransition"
     internal const val DEFAULT_TRANSITION_DURATION_MILLISECOND = 700
 }
 
@@ -58,19 +64,22 @@
  * Display for Composable content that displays a single pane of content at a time, but can move
  * that content in and out with customized transitions.
  *
- * The NavDisplay displays the content associated with the last key on the back stack in most
- * circumstances. If that content wants to be displayed as a dialog, as communicated by adding
- * [NavDisplay.isDialog] to a [NavEntry.featureMap], then the last key's content is a dialog and the
- * second to last key is a displayed in the background.
+ * The NavDisplay displays the content associated with the last key on the back stack.
  *
  * @param backstack the collection of keys that represents the state that needs to be handled
  * @param localProviders list of [NavLocalProvider] to add information to the provided entriess
  * @param modifier the modifier to be applied to the layout.
  * @param contentAlignment The [Alignment] of the [AnimatedContent]
- * @param enterTransition Default [EnterTransition] for all [NavEntry]s. Can be overridden
+ * @param enterTransition Default [EnterTransition] when navigating to [NavEntry]s. Can be
+ *   overridden individually for each [NavEntry] by passing in the entry's transitions through
+ *   [NavEntry.featureMap].
+ * @param exitTransition Default [ExitTransition] when navigating to [NavEntry]s. Can be overridden
  *   individually for each [NavEntry] by passing in the entry's transitions through
  *   [NavEntry.featureMap].
- * @param exitTransition Default [ExitTransition] for all [NavEntry]s. Can be overridden
+ * @param popEnterTransition Default [EnterTransition] when popping [NavEntry]s. Can be overridden
+ *   individually for each [NavEntry] by passing in the entry's transitions through
+ *   [NavEntry.featureMap].
+ * @param popExitTransition Default [ExitTransition] when popping [NavEntry]s. Can be overridden
  *   individually for each [NavEntry] by passing in the entry's transitions through
  *   [NavEntry.featureMap].
  * @param onBack a callback for handling system back presses
@@ -98,6 +107,20 @@
                     DEFAULT_TRANSITION_DURATION_MILLISECOND,
                 )
         ),
+    popEnterTransition: EnterTransition =
+        fadeIn(
+            animationSpec =
+                tween(
+                    DEFAULT_TRANSITION_DURATION_MILLISECOND,
+                )
+        ),
+    popExitTransition: ExitTransition =
+        fadeOut(
+            animationSpec =
+                tween(
+                    DEFAULT_TRANSITION_DURATION_MILLISECOND,
+                )
+        ),
     onBack: () -> Unit = { if (backstack is MutableList) backstack.removeAt(backstack.size - 1) },
     entryProvider: (key: T) -> NavEntry<out T>
 ) {
@@ -106,32 +129,30 @@
     val wrapperManager: NavWrapperManager = rememberNavWrapperManager(localProviders)
     BackHandler(backstack.size > 1, onBack)
     wrapperManager.PrepareBackStack(backStack = backstack)
-    val key = backstack.last()
-    val entry = entryProvider.invoke(key)
 
-    // Incoming entry defines transitions, otherwise it uses default transitions from NavDisplay
+    // Make a copy shallow copy so that transition.currentState and transition.targetState are
+    // different backstack instances. This ensures currentState reflects the old backstack when
+    // the backstack (targetState) is updated.
+    val newStack = backstack.toList()
+    val entry = entryProvider.invoke(newStack.last())
+
+    val transition = updateTransition(targetState = newStack, label = newStack.toString())
+    val isPop = isPop(transition.currentState, newStack)
+    // Incoming entry defines transitions, otherwise it uses default transitions from
+    // NavDisplay
     val finalEnterTransition =
-        entry.featureMap[NavDisplay.ENTER_TRANSITION_KEY] as? EnterTransition ?: enterTransition
-    val finalExitTransition =
-        entry.featureMap[NavDisplay.EXIT_TRANSITION_KEY] as? ExitTransition ?: exitTransition
-
-    val isDialog = entry.featureMap[NavDisplay.DIALOG_KEY] == true
-
-    // if there is a dialog, we should create a transition with the next to last entry instead.
-    val transition =
-        if (isDialog) {
-            if (backstack.size > 1) {
-                val previousKey = backstack[backstack.size - 2]
-                val previousEntry = entryProvider.invoke(previousKey)
-                updateTransition(targetState = previousEntry, label = previousKey.toString())
-            } else {
-                null
-            }
+        if (isPop) {
+            entry.featureMap[POP_ENTER_TRANSITION_KEY] as? EnterTransition ?: popEnterTransition
         } else {
-            updateTransition(targetState = entry, label = key.toString())
+            entry.featureMap[ENTER_TRANSITION_KEY] as? EnterTransition ?: enterTransition
         }
-
-    transition?.AnimatedContent(
+    val finalExitTransition =
+        if (isPop) {
+            entry.featureMap[POP_EXIT_TRANSITION_KEY] as? ExitTransition ?: popExitTransition
+        } else {
+            entry.featureMap[EXIT_TRANSITION_KEY] as? ExitTransition ?: exitTransition
+        }
+    transition.AnimatedContent(
         modifier = modifier,
         transitionSpec = {
             ContentTransform(
@@ -141,12 +162,25 @@
             )
         },
         contentAlignment = contentAlignment,
-        contentKey = { it.key }
-    ) { innerEntry ->
-        wrapperManager.ContentForEntry(innerEntry)
+        contentKey = { it.lastOrNull() }
+    ) { innerStack ->
+        // innerStack is not modified but List is still considered unstable in the world of
+        // compose - compose doesn't know for sure the key is the stable so it recomposes
+        // the content, unless we remember the key
+        val record = remember(innerStack.last()) { entryProvider.invoke(innerStack.last()) }
+        wrapperManager.ContentForEntry(record)
     }
+}
 
-    if (isDialog) {
-        Dialog(onBack) { wrapperManager.ContentForEntry(entry) }
-    }
+private fun <T : Any> isPop(oldBackStack: List<T>, newBackStack: List<T>): Boolean {
+    // entire stack replaced
+    if (oldBackStack.first() != newBackStack.first()) return false
+    // navigated
+    if (newBackStack.size > oldBackStack.size) return false
+
+    val divergingIndex =
+        newBackStack.indices.firstOrNull { index -> newBackStack[index] != oldBackStack[index] }
+    // if newBackStack never diverged from oldBackStack, then it is a clean subset of the oldStack
+    // and is a pop
+    return divergingIndex == null
 }
diff --git a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
index e5d19d9..e8fc674 100644
--- a/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
+++ b/navigation3/navigation3/src/commonMain/kotlin/androidx/navigation3/NavEntry.kt
@@ -26,7 +26,7 @@
  * @param featureMap map of the available features from a display
  * @param content content for this entry to be displayed when this entry is active
  */
-public class NavEntry<T : Any>(
+public open class NavEntry<T : Any>(
     public val key: T,
     public val featureMap: Map<String, Any> = emptyMap(),
     public val content: @Composable (T) -> Unit,
diff --git a/paging/paging-compose/src/androidInstrumentedTest/kotlin/androidx/paging/compose/LazyPagingItemsTest.kt b/paging/paging-compose/src/androidInstrumentedTest/kotlin/androidx/paging/compose/LazyPagingItemsTest.kt
index dc64222..edf4bf1 100644
--- a/paging/paging-compose/src/androidInstrumentedTest/kotlin/androidx/paging/compose/LazyPagingItemsTest.kt
+++ b/paging/paging-compose/src/androidInstrumentedTest/kotlin/androidx/paging/compose/LazyPagingItemsTest.kt
@@ -263,8 +263,8 @@
             }
         }
 
-        val idMinus1 = rule.onNodeWithTag("-1").semanticsId()
-        val id0 = rule.onNodeWithTag("0").semanticsId()
+        val idMinus1 = rule.onNodeWithTag("-1").fetchSemanticsNode().id
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
         rule.runOnIdle {
             runBlocking {
                 state.scrollToItem(2)
@@ -327,8 +327,8 @@
 
         rule.waitUntil { loadedItem6 }
 
-        val idMinus1 = rule.onNodeWithTag("-1").semanticsId()
-        val id0 = rule.onNodeWithTag("0").semanticsId()
+        val idMinus1 = rule.onNodeWithTag("-1").fetchSemanticsNode().id
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
@@ -381,8 +381,8 @@
             }
         }
 
-        val idMinus1 = rule.onNodeWithTag("-1").semanticsId()
-        val id0 = rule.onNodeWithTag("0").semanticsId()
+        val idMinus1 = rule.onNodeWithTag("-1").fetchSemanticsNode().id
+        val id0 = rule.onNodeWithTag("0").fetchSemanticsNode().id
 
         rule.runOnIdle {
             runBlocking {
diff --git a/pdf/integration-tests/testapp/src/main/AndroidManifest.xml b/pdf/integration-tests/testapp/src/main/AndroidManifest.xml
index fe5943bc..d0228a0 100644
--- a/pdf/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/pdf/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -27,7 +27,6 @@
         android:theme="@style/AppTheme">
         <activity
             android:name=".MainActivity"
-            android:configChanges="orientation|screenSize"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/pdf/pdf-viewer/src/androidTest/kotlin/androidx/pdf/view/PdfViewZoomStateTest.kt b/pdf/pdf-viewer/src/androidTest/kotlin/androidx/pdf/view/PdfViewZoomStateTest.kt
new file mode 100644
index 0000000..c04af8b
--- /dev/null
+++ b/pdf/pdf-viewer/src/androidTest/kotlin/androidx/pdf/view/PdfViewZoomStateTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.pdf.view
+
+import android.graphics.Point
+import android.graphics.PointF
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import androidx.test.core.app.ActivityScenario
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class PdfViewZoomStateTest {
+
+    private lateinit var activityScenario: ActivityScenario<PdfViewTestActivity>
+
+    @Before
+    fun setup() {
+        activityScenario = ActivityScenario.launch(PdfViewTestActivity::class.java)
+    }
+
+    @After
+    fun tearDown() {
+        PdfViewTestActivity.onCreateCallback = {}
+        activityScenario.close()
+    }
+
+    private fun setupPdfView(fakePdfDocument: FakePdfDocument?) {
+        PdfViewTestActivity.onCreateCallback = { activity ->
+            val container = FrameLayout(activity)
+            val pdfView =
+                PdfView(activity).apply {
+                    pdfDocument = fakePdfDocument
+                    id = PDF_VIEW_ID
+                    minZoom = 0.5f
+                    maxZoom = 5.0f
+                }
+            container.addView(pdfView, ViewGroup.LayoutParams(PAGE_WIDTH, PAGE_HEIGHT * 2))
+            activity.setContentView(container)
+        }
+    }
+
+    @Test
+    fun testInitialZoom_fitWidth() = runTest {
+        val fakePdfDocument = FakePdfDocument(List(20) { Point(PAGE_WIDTH, PAGE_HEIGHT) })
+
+        setupPdfView(fakePdfDocument)
+
+        with(ActivityScenario.launch(PdfViewTestActivity::class.java)) {
+            fakePdfDocument.waitForLayout(untilPage = 3)
+            onView(withId(PDF_VIEW_ID)).check { view, noViewFoundException ->
+                view ?: throw noViewFoundException
+                val pdfView = view as PdfView
+                assertThat(pdfView.isInitialZoomDone).isTrue()
+                assertThat(pdfView.zoom).isWithin(0.01f).of(1.0f)
+            }
+        }
+    }
+
+    @Test
+    fun testGetDefaultZoom_fitWidth() = runTest {
+        val fakePdfDocument = FakePdfDocument(List(20) { Point(PAGE_WIDTH, PAGE_HEIGHT) })
+
+        setupPdfView(fakePdfDocument)
+        activityScenario.recreate()
+
+        activityScenario.onActivity { activity ->
+            val pdfView = activity.findViewById<PdfView>(PDF_VIEW_ID)
+            pdfView.zoom = 2.0f
+            val expectedZoom = 1.0f
+            val actualZoom = pdfView.getDefaultZoom()
+            assertThat(actualZoom).isWithin(0.01f).of(expectedZoom)
+        }
+    }
+
+    @Test
+    fun testRestoreUserZoomAndScrollPosition() = runTest {
+        val fakePdfDocument = FakePdfDocument(List(20) { Point(PAGE_WIDTH, PAGE_HEIGHT) })
+        val savedZoom = 2.5f
+        val savedScrollPosition = PointF(100f, PAGE_HEIGHT * 1f / savedZoom)
+
+        setupPdfView(fakePdfDocument)
+        activityScenario.recreate()
+
+        activityScenario.onActivity { activity ->
+            val pdfView = activity.findViewById<PdfView>(PDF_VIEW_ID)
+            pdfView.zoom = savedZoom
+            pdfView.scrollTo(
+                (savedScrollPosition.x * savedZoom - pdfView.viewportWidth / 2f).toInt(),
+                (savedScrollPosition.y * savedZoom - pdfView.viewportHeight / 2f).toInt()
+            )
+            pdfView.isInitialZoomDone = true
+        }
+
+        activityScenario.recreate()
+
+        onView(withId(PDF_VIEW_ID)).check { view, _ ->
+            view as PdfView
+            assertThat(view.zoom).isWithin(0.01f).of(savedZoom)
+            val expectedScrollX =
+                (savedScrollPosition.x * savedZoom - view.viewportWidth / 2f).toInt()
+            val expectedScrollY =
+                (savedScrollPosition.y * savedZoom - view.viewportHeight / 2f).toInt()
+            assertThat(view.scrollX).isEqualTo(expectedScrollX)
+            assertThat(view.scrollY).isEqualTo(expectedScrollY)
+        }
+    }
+}
+
+/** Arbitrary fixed ID for PdfView */
+private const val PDF_VIEW_ID = 123456789
+private const val PAGE_WIDTH = 500
+private const val PAGE_HEIGHT = 800
+
+/** The height of the viewport, minus padding */
+val PdfView.viewportHeight: Int
+    get() = bottom - top - paddingBottom - paddingTop
+
+/** The width of the viewport, minus padding */
+val PdfView.viewportWidth: Int
+    get() = right - left - paddingRight - paddingLeft
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/AccessibilityPageHelper.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/AccessibilityPageHelper.kt
index 4f23256..1850e02 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/AccessibilityPageHelper.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/AccessibilityPageHelper.kt
@@ -41,8 +41,8 @@
     private val pageManager: PageManager
 ) : ExploreByTouchHelper(pdfView) {
 
-    private var gotoLinks: MutableList<PdfPageGotoLinkContent> = mutableListOf()
-    private var urlLinks: MutableList<PdfPageLinkContent> = mutableListOf()
+    private val gotoLinks: MutableMap<Int, LinkWrapper<PdfPageGotoLinkContent>> = mutableMapOf()
+    private val urlLinks: MutableMap<Int, LinkWrapper<PdfPageLinkContent>> = mutableMapOf()
     private val totalPages = pdfView.pdfDocument?.pageCount ?: 0
     private var isLinksLoaded = false
 
@@ -56,19 +56,21 @@
             loadPageLinks()
         }
 
-        // Check if the coordinates fall within any of the gotoLinks bounds
-        gotoLinks.forEachIndexed { index, gotoLink ->
-            if (gotoLink.bounds.any { it.contains(contentX.toFloat(), contentY.toFloat()) }) {
-                return index + totalPages
+        gotoLinks.entries
+            .find { (_, wrapper) ->
+                wrapper.linkBounds.contains(contentX.toFloat(), contentY.toFloat())
             }
-        }
+            ?.let {
+                return it.key
+            }
 
-        // Check if the coordinates fall within any of the urlLinks bounds
-        urlLinks.forEachIndexed { index, urlLink ->
-            if (urlLink.bounds.any { it.contains(contentX.toFloat(), contentY.toFloat()) }) {
-                return index + totalPages + gotoLinks.size
+        urlLinks.entries
+            .find { (_, wrapper) ->
+                wrapper.linkBounds.contains(contentX.toFloat(), contentY.toFloat())
             }
-        }
+            ?.let {
+                return it.key
+            }
 
         // Check if the coordinates fall within the visible page bounds
         return (visiblePages.lower..visiblePages.upper).firstOrNull { page ->
@@ -80,14 +82,12 @@
 
     public override fun getVisibleVirtualViews(virtualViewIds: MutableList<Int>) {
         val visiblePages = pageLayoutManager.visiblePages.value
-        virtualViewIds.addAll(visiblePages.lower..visiblePages.upper)
-
         loadPageLinks()
 
-        gotoLinks.forEachIndexed { index, _ -> virtualViewIds.add(totalPages + index) }
-
-        urlLinks.forEachIndexed { index, _ ->
-            virtualViewIds.add(totalPages + gotoLinks.size + index)
+        virtualViewIds.apply {
+            addAll(visiblePages.lower..visiblePages.upper)
+            addAll(gotoLinks.keys)
+            addAll(urlLinks.keys)
         }
     }
 
@@ -97,10 +97,13 @@
     ) {
         if (!isLinksLoaded) loadPageLinks()
 
-        if (virtualViewId < totalPages) {
-            populateNodeForPage(virtualViewId, node)
-        } else {
-            populateNodeForLink(virtualViewId, node)
+        when {
+            virtualViewId < totalPages -> populateNodeForPage(virtualViewId, node)
+            else -> {
+                // Populate node for GoTo links and URL links
+                gotoLinks[virtualViewId]?.let { populateGotoLinkNode(it, node) }
+                urlLinks[virtualViewId]?.let { populateUrlLinkNode(it, node) }
+            }
         }
     }
 
@@ -134,40 +137,61 @@
         }
     }
 
-    private fun populateNodeForLink(virtualViewId: Int, node: AccessibilityNodeInfoCompat) {
-        val adjustedId = virtualViewId - totalPages
-        if (adjustedId < gotoLinks.size) {
-            populateGotoLinkNode(adjustedId, node)
-        } else {
-            populateUrlLinkNode(adjustedId - gotoLinks.size, node)
-        }
-    }
+    private fun populateGotoLinkNode(
+        linkWrapper: LinkWrapper<PdfPageGotoLinkContent>,
+        node: AccessibilityNodeInfoCompat
+    ) {
+        val bounds = scalePageBounds(linkWrapper.linkBounds, pdfView.zoom)
 
-    private fun populateGotoLinkNode(linkIndex: Int, node: AccessibilityNodeInfoCompat) {
-        val gotoLink = gotoLinks[linkIndex]
-        val bounds = scalePageBounds(gotoLink.bounds.first(), pdfView.zoom)
         node.apply {
             contentDescription =
                 pdfView.context.getString(
                     R.string.desc_goto_link,
-                    gotoLink.destination.pageNumber + 1
+                    linkWrapper.content.destination.pageNumber + 1
                 )
-            setBoundsInScreenFromBoundsInParent(node, bounds)
+            setBoundsInScreenFromBoundsInParent(this, bounds)
             isFocusable = true
         }
     }
 
-    private fun populateUrlLinkNode(linkIndex: Int, node: AccessibilityNodeInfoCompat) {
-        val urlLink = urlLinks[linkIndex]
-        val bounds = scalePageBounds(urlLink.bounds.first(), pdfView.zoom)
+    private fun populateUrlLinkNode(
+        linkWrapper: LinkWrapper<PdfPageLinkContent>,
+        node: AccessibilityNodeInfoCompat
+    ) {
+        val bounds = scalePageBounds(linkWrapper.linkBounds, pdfView.zoom)
         node.apply {
             contentDescription =
-                ExternalLinks.getDescription(urlLink.uri.toString(), pdfView.context)
+                ExternalLinks.getDescription(linkWrapper.content.uri.toString(), pdfView.context)
             setBoundsInScreenFromBoundsInParent(node, bounds)
             isFocusable = true
         }
     }
 
+    /**
+     * Calculates the adjusted bounds of a link relative to the full content of the PDF.
+     *
+     * @param pageNumber The 0-indexed page number.
+     * @param linkBounds The bounds of the link on the page.
+     * @return The adjusted bounds in the content coordinate system.
+     */
+    fun getLinkBounds(pageNumber: Int, linkBounds: RectF): RectF {
+        val pageBounds =
+            pageLayoutManager.getPageLocation(pageNumber, pdfView.getVisibleAreaInContentCoords())
+        return RectF(
+            linkBounds.left + pageBounds.left,
+            linkBounds.top + pageBounds.top,
+            linkBounds.right + pageBounds.left,
+            linkBounds.bottom + pageBounds.top
+        )
+    }
+
+    /**
+     * Scales the bounds of a page based on the current zoom level.
+     *
+     * @param bounds The original bounds to scale.
+     * @param zoom The zoom level.
+     * @return The scaled bounds as a Rect.
+     */
     @VisibleForTesting
     fun scalePageBounds(bounds: RectF, zoom: Float): Rect {
         return Rect(
@@ -178,6 +202,12 @@
         )
     }
 
+    /**
+     * Loads the links for the visible pages.
+     *
+     * This method fetches the GoTo links and URL links for the currently visible pages and stores
+     * them in the corresponding maps.
+     */
     fun loadPageLinks() {
         val visiblePages = pageLayoutManager.visiblePages.value
 
@@ -185,10 +215,20 @@
         gotoLinks.clear()
         urlLinks.clear()
 
+        var cumulativeId = totalPages
+
         (visiblePages.lower..visiblePages.upper).forEach { pageIndex ->
             pageManager.pages[pageIndex]?.links?.let { links ->
-                links.gotoLinks.let { gotoLinks.addAll(it) }
-                links.externalLinks.let { urlLinks.addAll(it) }
+                links.gotoLinks.forEach { link ->
+                    gotoLinks[cumulativeId] =
+                        LinkWrapper(pageIndex, link, getLinkBounds(pageIndex, link.bounds.first()))
+                    cumulativeId++
+                }
+                links.externalLinks.forEach { link ->
+                    urlLinks[cumulativeId] =
+                        LinkWrapper(pageIndex, link, getLinkBounds(pageIndex, link.bounds.first()))
+                    cumulativeId++
+                }
             }
         }
         isLinksLoaded = true
@@ -243,3 +283,13 @@
         }
     }
 }
+
+/**
+ * A wrapper class for links in the PDF document.
+ *
+ * @param T The type of link content (GotoLink or URL link).
+ * @param pageNumber The 0-indexed page number where the link is located.
+ * @param content The link's content (GotoLink or URL link).
+ * @param linkBounds The link's bounds in the full PDF's content coordinates.
+ */
+private data class LinkWrapper<T>(val pageNumber: Int, val content: T, val linkBounds: RectF)
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
index 8b223f0..f8c0f61 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/BitmapFetcher.kt
@@ -24,12 +24,11 @@
 import androidx.annotation.MainThread
 import androidx.annotation.VisibleForTesting
 import androidx.pdf.PdfDocument
+import androidx.pdf.util.RectUtils
 import kotlin.math.roundToInt
-import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.ensureActive
-import kotlinx.coroutines.job
 import kotlinx.coroutines.launch
 
 /**
@@ -56,6 +55,7 @@
      */
     private val maxTileBackgroundSizePx = Point(maxBitmapSizePx.x / 2, maxBitmapSizePx.y / 2)
 
+    /** True if this fetcher is ready to fetch bitmaps for the page */
     var isActive: Boolean = false
         set(value) {
             // Debounce setting the field to the same value
@@ -64,41 +64,102 @@
             if (field) onActive() else onInactive()
         }
 
+    /** The bitmaps to draw for this page, as [PageContents] */
     @get:MainThread var pageContents: PageContents? = null
 
+    /** The [PdfDocument.BitmapSource] from which to obtain [Bitmap]s, only used while [isActive] */
     private var bitmapSource: PdfDocument.BitmapSource? = null
-    @VisibleForTesting var currentRenderingScale: Float? = null
-    @VisibleForTesting var renderingJob: Job? = null
 
-    /**
-     * Notify this fetcher that the zoom level / scale factor of the UI has changed, and that it
-     * ought to consider fetching new bitmaps
-     */
-    fun onScaleChanged(scale: Float) {
-        if (!shouldRenderNewBitmaps(scale)) return
+    /** The scale, i.e. zoom level for which we're actively fetching [Bitmap]s */
+    @VisibleForTesting var currentFetchingScale: Float? = null
 
-        currentRenderingScale = scale
-        renderingJob?.cancel()
-        renderingJob =
-            if (needsTiling(scale)) {
-                fetchTiles(scale)
-            } else {
-                fetchNewBitmap(scale)
-            }
-        renderingJob?.invokeOnCompletion { cause ->
-            // We only want to reset these states when we completed naturally
-            if (cause is CancellationException) return@invokeOnCompletion
-            renderingJob = null
-            currentRenderingScale = null
+    /** The [BitmapRequestHandle] for any ongoing fetch */
+    @VisibleForTesting var fetchingWorkHandle: BitmapRequestHandle? = null
+
+    /** Update the view area and scale for which we should be fetching bitmaps */
+    fun updateViewProperties(scale: Float, viewArea: Rect) {
+        // Scale the provided viewArea, and clip it to the scaled bounds of the page
+        // Carefully avoid mutating the provided Rect
+        val scaledViewArea = Rect(viewArea)
+        RectUtils.scale(scaledViewArea, scale)
+        scaledViewArea.intersect(0, 0, (pageSize.x * scale).toInt(), (pageSize.y * scale).toInt())
+        if (shouldFetchNewContents(scale)) {
+            // Scale has changed, fetch entirely new PageContents
+            fetchNewContents(scale, scaledViewArea)
+        } else {
+            // View area has changed, fetch new tiles and discard obsolete ones IFF we're tiling
+            maybeUpdateTiling(scale, scaledViewArea)
         }
     }
 
-    private fun shouldRenderNewBitmaps(scale: Float): Boolean {
-        val renderingAtCurrentScale =
-            currentRenderingScale == scale && renderingJob?.isActive == true
-        val renderedAtCurrentScale = pageContents?.let { it.renderedScale == scale } ?: false
+    /** Discard all bitmaps in the current tiling */
+    fun discardTileBitmaps() {
+        (pageContents as? TileBoard)?.let { for (tile in it.tiles) tile.bitmap = null }
+    }
 
-        return !renderedAtCurrentScale && !renderingAtCurrentScale
+    private fun maybeUpdateTiling(scale: Float, scaledViewArea: Rect) {
+        // Exit early if we're not tiling
+        val currentTileBoard = pageContents as? TileBoard ?: return
+        val currentTilingWork = fetchingWorkHandle as? TileBoardRequestHandle
+        val tileRequests = mutableMapOf<Int, SingleBitmapRequestHandle>()
+        var tileJob: Job? = null
+        for (tile in currentTileBoard.tiles) {
+            val ongoingRequest = currentTilingWork?.tileRequestHandles?.get(tile.index)
+            if (
+                tile.rectPx.intersects(
+                    scaledViewArea.left,
+                    scaledViewArea.top,
+                    scaledViewArea.right,
+                    scaledViewArea.bottom
+                )
+            ) {
+                // Tile is visible, make sure we have, or have requested, a Bitmap for it
+                if (ongoingRequest?.isActive == true) {
+                    // Continue tracking the active request for this tile
+                    tileRequests[tile.index] = ongoingRequest
+                } else if (tile.bitmap == null) {
+                    // Make a new request for this tile
+                    tileJob = fetchBitmap(tile, scale, tileJob)
+                    tileRequests[tile.index] = SingleBitmapRequestHandle(tileJob)
+                }
+            } else {
+                // Tile is no longer visible, cancel any active request and clean up the Bitmap
+                ongoingRequest?.cancel()
+                tile.bitmap = null
+            }
+        }
+        if (tileRequests.isNotEmpty()) {
+            fetchingWorkHandle =
+                TileBoardRequestHandle(tileRequests, currentTilingWork?.backgroundRequestHandle)
+            currentFetchingScale = scale
+        }
+    }
+
+    /**
+     * Notify this fetcher that the zoom level / scale factor of the UI has changed, and that it
+     * ought to fetch new bitmaps
+     */
+    private fun fetchNewContents(scale: Float, scaledViewArea: Rect) {
+        fetchingWorkHandle?.cancel()
+        fetchingWorkHandle =
+            if (needsTiling(scale)) {
+                fetchTiles(scale, scaledViewArea)
+            } else {
+                fetchNewBitmap(scale)
+            }
+        currentFetchingScale = scale
+    }
+
+    /**
+     * Returns true if this fetcher should start fetching a net-new [PageContents], i.e. if the
+     * scaled has changed since we started or finished fetching the previous set of Bitmaps
+     */
+    private fun shouldFetchNewContents(scale: Float): Boolean {
+        val fetchingAtCurrentScale =
+            currentFetchingScale == scale && fetchingWorkHandle?.isActive == true
+        val fetchedAtCurrentScale = pageContents?.let { it.bitmapScale == scale } == true
+
+        return !fetchedAtCurrentScale && !fetchingAtCurrentScale
     }
 
     /** Prepare to start fetching bitmaps */
@@ -111,73 +172,102 @@
      * this fetcher
      */
     private fun onInactive() {
-        currentRenderingScale = null
+        currentFetchingScale = null
         pageContents = null
-        renderingJob?.cancel()
-        renderingJob = null
+        fetchingWorkHandle?.cancel()
+        fetchingWorkHandle = null
         bitmapSource?.close()
         bitmapSource = null
     }
 
     /** Fetch a [FullPageBitmap] */
-    private fun fetchNewBitmap(scale: Float): Job {
-        return backgroundScope.launch {
-            val size = limitBitmapSize(scale, maxBitmapSizePx)
-            // If our BitmapSource is null that means this fetcher is inactive and we should
-            // stop what we're doing
-            val bitmap = bitmapSource?.getBitmap(size) ?: return@launch
-            ensureActive()
-            pageContents = FullPageBitmap(bitmap, scale)
-            onPageUpdate()
-        }
+    private fun fetchNewBitmap(scale: Float): SingleBitmapRequestHandle {
+        val job =
+            backgroundScope.launch {
+                val size = limitBitmapSize(scale, maxBitmapSizePx)
+                // If our BitmapSource is null that means this fetcher is inactive and we should
+                // stop what we're doing
+                val bitmap = bitmapSource?.getBitmap(size) ?: return@launch
+                ensureActive()
+                pageContents = FullPageBitmap(bitmap, scale)
+                onPageUpdate()
+            }
+        return SingleBitmapRequestHandle(job)
     }
 
     /** Fetch a [TileBoard] */
-    private fun fetchTiles(scale: Float): Job {
+    private fun fetchTiles(scale: Float, scaledViewArea: Rect): TileBoardRequestHandle {
         val pageSizePx = Point((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt())
         val tileBoard = TileBoard(tileSizePx, pageSizePx, scale)
-        // Re-use an existing background bitmap if we have one to avoid unnecessary re-rendering
+        // Re-use an existing background bitmap if we have one to avoid unnecessary re-fetching
         // and jank
-        val prevBackground = (tileBoard as? TileBoard)?.backgroundBitmap
+        val prevBackground = tileBoard.backgroundBitmap
         if (prevBackground != null) {
             tileBoard.backgroundBitmap = prevBackground
             pageContents = tileBoard
             onPageUpdate()
         }
-        return backgroundScope.launch {
-            // Render a new background bitmap if we must
+        val backgroundRequest =
             if (prevBackground == null) {
-                // If our BitmapSource is null that means this fetcher is inactive and we should
-                // stop what we're doing
-                val backgroundSize = limitBitmapSize(scale, maxTileBackgroundSizePx)
-                val bitmap = bitmapSource?.getBitmap(backgroundSize) ?: return@launch
-                pageContents = tileBoard
-                ensureActive()
-                tileBoard.backgroundBitmap = bitmap
-                onPageUpdate()
+                val job =
+                    backgroundScope.launch {
+                        ensureActive()
+                        val backgroundSize = limitBitmapSize(scale, maxTileBackgroundSizePx)
+                        val bitmap = bitmapSource?.getBitmap(backgroundSize) ?: return@launch
+                        pageContents = tileBoard
+                        ensureActive()
+                        tileBoard.backgroundBitmap = bitmap
+                        onPageUpdate()
+                    }
+                SingleBitmapRequestHandle(job)
+            } else {
+                null
             }
-            for (tile in tileBoard.tiles) {
-                renderBitmap(tile, coroutineContext.job, scale)
+        val tileRequests = mutableMapOf<Int, SingleBitmapRequestHandle>()
+        // Used to sequence requests so tiles are loaded left-to-right and top-to-bottom
+        var tileJob: Job? = null
+        for (tile in tileBoard.tiles) {
+            val tileRect = tile.rectPx
+            if (
+                scaledViewArea.intersects(
+                    tileRect.left,
+                    tileRect.top,
+                    tileRect.right,
+                    tileRect.bottom
+                )
+            ) {
+                tileJob = fetchBitmap(tile, scale, tileJob)
+                tileRequests[tile.index] = SingleBitmapRequestHandle(tileJob)
             }
         }
+        return TileBoardRequestHandle(tileRequests.toMap(), backgroundRequest)
     }
 
-    /** Render a [Bitmap] for this [TileBoard.Tile] */
-    private suspend fun renderBitmap(tile: TileBoard.Tile, thisJob: Job, scale: Float) {
-        thisJob.ensureActive()
-        val left = tile.offsetPx.x
-        val top = tile.offsetPx.y
-        val tileRect = Rect(left, top, left + tile.exactSizePx.x, top + tile.exactSizePx.y)
-        // If our BitmapSource is null that means this fetcher is inactive and we should
-        // stop what we're doing
-        val bitmap =
-            bitmapSource?.getBitmap(
-                Size((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt()),
-                tileRect
-            ) ?: return
-        thisJob.ensureActive()
-        tile.bitmap = bitmap
-        onPageUpdate()
+    /**
+     * Fetch a [Bitmap] for this [TileBoard.Tile]
+     *
+     * @param tile the [TileBoard.Tile] to fetch a bitmap for
+     * @param scale the scale factor of the bitmap
+     * @param prevJob the [Job] that is fetching a bitmap for the tile left or above [tile], i.e. to
+     *   guarantee tiles are loaded left-to-right and top-to-bottom
+     */
+    private fun fetchBitmap(tile: TileBoard.Tile, scale: Float, prevJob: Job?): Job {
+        val job =
+            backgroundScope.launch {
+                prevJob?.join()
+                ensureActive()
+                // If our BitmapSource is null that means this fetcher is inactive and we should
+                // stop what we're doing
+                val bitmap =
+                    bitmapSource?.getBitmap(
+                        Size((pageSize.x * scale).roundToInt(), (pageSize.y * scale).roundToInt()),
+                        tile.rectPx
+                    ) ?: return@launch
+                ensureActive()
+                tile.bitmap = bitmap
+                onPageUpdate()
+            }
+        return job
     }
 
     /** True if the [pageSize] * [scale] exceeds [maxBitmapSizePx] */
@@ -206,13 +296,56 @@
     }
 }
 
+/** Represents a cancellable handle to a request for one or more [Bitmap]s */
+internal sealed interface BitmapRequestHandle {
+    /** True if this request is active */
+    val isActive: Boolean
+
+    /** Cancel this request completely */
+    fun cancel()
+}
+
+/** Cancellable [BitmapRequestHandle] for a single [Bitmap] */
+internal class SingleBitmapRequestHandle(private val job: Job) : BitmapRequestHandle {
+    override val isActive: Boolean
+        get() = job.isActive
+
+    override fun cancel() {
+        job.cancel()
+    }
+}
+
+/**
+ * Cancellable [BitmapRequestHandle] for a full [TileBoard], composing multiple
+ * [SingleBitmapRequestHandle] for the low-res background and each high-res tile
+ */
+internal class TileBoardRequestHandle(
+    /** Map of [TileBoard.Tile.index] to a [BitmapRequestHandle] to fetch that tile's bitmap */
+    val tileRequestHandles: Map<Int, SingleBitmapRequestHandle>,
+    /**
+     * [SingleBitmapRequestHandle] to fetch a low-res background for this tiling, or null if we
+     * re-used the background from a previous tiling
+     */
+    val backgroundRequestHandle: SingleBitmapRequestHandle? = null
+) : BitmapRequestHandle {
+    override val isActive: Boolean
+        get() =
+            tileRequestHandles.values.any { it.isActive } ||
+                backgroundRequestHandle?.isActive == true
+
+    override fun cancel() {
+        tileRequestHandles.values.forEach { it.cancel() }
+        backgroundRequestHandle?.cancel()
+    }
+}
+
 /** Represents the [Bitmap] or [Bitmap]s used to render this page */
 internal sealed interface PageContents {
-    val renderedScale: Float
+    val bitmapScale: Float
 }
 
 /** A singular [Bitmap] depicting the full page, when full page rendering is used */
-internal class FullPageBitmap(val bitmap: Bitmap, override val renderedScale: Float) : PageContents
+internal class FullPageBitmap(val bitmap: Bitmap, override val bitmapScale: Float) : PageContents
 
 /**
  * A set of [Bitmap]s that depict the full page as a rectangular grid of individual bitmap tiles.
@@ -221,7 +354,7 @@
 internal class TileBoard(
     val tileSizePx: Point,
     val pageSizePx: Point,
-    override val renderedScale: Float
+    override val bitmapScale: Float
 ) : PageContents {
 
     /** The low res background [Bitmap] for this [TileBoard] */
@@ -239,7 +372,7 @@
     val tiles = Array(numRows * numCols) { index -> Tile(index) }
 
     /** An individual [Tile] in this [TileBoard] */
-    inner class Tile(index: Int) {
+    inner class Tile(val index: Int) {
         /** The x position of this tile in the tile board */
         private val rowIdx = index / numCols
 
@@ -248,7 +381,7 @@
 
         /**
          * The offset of this [Tile] from the origin of the page in pixels, used in computations
-         * where an exact pixel size is expected, e.g. rendering bitmaps
+         * where an exact pixel size is expected, e.g. fetching bitmaps
          */
         val offsetPx = Point(colIdx * tileSizePx.x, rowIdx * tileSizePx.y)
 
@@ -259,6 +392,10 @@
                 minOf(tileSizePx.y, pageSizePx.y - offsetPx.y),
             )
 
+        /** The exact pixel location of this tile in the scaled page */
+        val rectPx =
+            Rect(offsetPx.x, offsetPx.y, offsetPx.x + exactSizePx.x, offsetPx.y + exactSizePx.y)
+
         /** The high res [Bitmap] for this [Tile] */
         var bitmap: Bitmap? = null
     }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
index 48d9f6f..5cfabbc 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/Page.kt
@@ -39,7 +39,7 @@
     /** The 0-based index of this page in the PDF */
     private val pageNum: Int,
     /** The size of this PDF page, in content coordinates */
-    pageSizePx: Point,
+    pageSize: Point,
     /** The [PdfDocument] this [Page] belongs to */
     private val pdfDocument: PdfDocument,
     /** The [CoroutineScope] to use for background work */
@@ -64,7 +64,7 @@
     private val bitmapFetcher =
         BitmapFetcher(
             pageNum,
-            pageSizePx,
+            pageSize,
             pdfDocument,
             backgroundScope,
             maxBitmapSizePx,
@@ -91,17 +91,34 @@
     internal var links: PdfDocument.PdfPageLinks? = null
         private set
 
-    fun updateState(zoom: Float, isFlinging: Boolean = false) {
+    /**
+     * Puts this page into a "visible" state, and / or updates various properties related to the
+     * page's visible state
+     *
+     * @param zoom the current scale
+     * @param viewArea the portion of the page that's visible, in content coordinates
+     * @param stablePosition true if position is not actively changing, e.g. during a fling
+     */
+    fun setVisible(zoom: Float, viewArea: Rect, stablePosition: Boolean = true) {
         bitmapFetcher.isActive = true
-        bitmapFetcher.onScaleChanged(zoom)
-        if (!isFlinging) {
+        bitmapFetcher.updateViewProperties(zoom, viewArea)
+        if (stablePosition) {
             maybeFetchLinks()
             if (isTouchExplorationEnabled) {
-                fetchPageText()
+                maybeFetchPageText()
             }
         }
     }
 
+    /**
+     * Puts this page into a "nearly visible" state, discarding only high res bitmaps and retaining
+     * lighter weight data in case the page becomes visible again
+     */
+    fun setNearlyVisible() {
+        bitmapFetcher.discardTileBitmaps()
+    }
+
+    /** Puts this page into an "invisible" state, i.e. retaining only the minimum data required */
     fun setInvisible() {
         bitmapFetcher.isActive = false
         pageText = null
@@ -112,7 +129,7 @@
         fetchLinksJob = null
     }
 
-    private fun fetchPageText() {
+    private fun maybeFetchPageText() {
         if (fetchPageTextJob?.isActive == true || pageText != null) return
 
         fetchPageTextJob =
@@ -171,7 +188,7 @@
                 canvas.drawBitmap(
                     bitmap, /* src */
                     null,
-                    locationForTile(tile, tileBoard.renderedScale, locationInView),
+                    locationForTile(tile, tileBoard.bitmapScale, locationInView),
                     BMP_PAINT
                 )
             }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
index 2844056..90156e5 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageLayoutManager.kt
@@ -21,6 +21,7 @@
 import android.graphics.Rect
 import android.graphics.RectF
 import android.util.Range
+import android.util.SparseArray
 import androidx.pdf.PdfDocument
 import kotlin.math.ceil
 import kotlin.math.floor
@@ -107,6 +108,30 @@
     }
 
     /**
+     * Returns a [SparseArray] containing [Rect]s indicating the visible region of each visible
+     * page, in page coordinates.
+     */
+    fun getVisiblePageAreas(pages: Range<Int>, viewport: Rect): SparseArray<Rect> {
+        val ret = SparseArray<Rect>(pages.upper - pages.lower + 1)
+        for (i in pages.lower..pages.upper) {
+            ret.put(i, getPageVisibleArea(i, viewport))
+        }
+        return ret
+    }
+
+    private fun getPageVisibleArea(pageNum: Int, viewport: Rect): Rect {
+        val pageLocation = getPageLocation(pageNum, viewport)
+        val pageWidth = pageLocation.right - pageLocation.left
+        val pageHeight = pageLocation.bottom - pageLocation.top
+        return Rect(
+            maxOf(viewport.left - pageLocation.left, 0),
+            maxOf(viewport.top - pageLocation.top, 0),
+            minOf(viewport.right - pageLocation.left, pageWidth),
+            minOf(viewport.bottom - pageLocation.top, pageHeight),
+        )
+    }
+
+    /**
      * Returns the current View-coordinate location of a 0-indexed [pageNum] given the [viewport]
      */
     fun getPageLocation(pageNum: Int, viewport: Rect): Rect {
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
index 322ee54..e32dbae 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PageManager.kt
@@ -78,29 +78,41 @@
     private val highlights: MutableMap<Int, MutableList<Highlight>> = mutableMapOf()
 
     /**
-     * Updates the internal state of [Page]s owned by this manager in response to a viewport change
+     * Updates the visibility state of [Page]s owned by this manager.
+     *
+     * @param visiblePageAreas the visible area of each visible page, in page coordinates
+     * @param currentZoomLevel the current zoom level
+     * @param stablePosition true if we don't believe our position is actively changing
      */
-    fun maybeUpdatePageState(
-        visiblePages: Range<Int>,
+    fun updatePageVisibilities(
+        visiblePageAreas: SparseArray<Rect>,
         currentZoomLevel: Float,
-        isFlinging: Boolean
+        stablePosition: Boolean
     ) {
         // Start preparing UI for visible pages
-        for (i in visiblePages.lower..visiblePages.upper) {
-            pages[i]?.updateState(currentZoomLevel, isFlinging)
+        visiblePageAreas.keyIterator().forEach { pageNum ->
+            pages[pageNum]?.setVisible(
+                currentZoomLevel,
+                visiblePageAreas.get(pageNum),
+                stablePosition
+            )
         }
 
-        // Hide pages that are well outside the viewport. We deliberately don't set pages that
-        // are within nearPages, but outside visible pages to invisible to avoid rendering churn
-        // for pages likely to return to the viewport.
+        // We put pages that are near the viewport in a "nearly visible" state where some data is
+        // retained. We release all data from pages well outside the viewport
         val nearPages =
             Range(
-                maxOf(0, visiblePages.lower - pagePrefetchRadius),
-                minOf(visiblePages.upper + pagePrefetchRadius, pdfDocument.pageCount - 1),
+                maxOf(0, visiblePageAreas.keyAt(0) - pagePrefetchRadius),
+                minOf(
+                    visiblePageAreas.keyAt(visiblePageAreas.size() - 1) + pagePrefetchRadius,
+                    pdfDocument.pageCount - 1
+                ),
             )
         for (pageNum in pages.keyIterator()) {
             if (pageNum < nearPages.lower || pageNum > nearPages.upper) {
                 pages[pageNum]?.setInvisible()
+            } else if (!visiblePageAreas.contains(pageNum)) {
+                pages[pageNum]?.setNearlyVisible()
             }
         }
     }
@@ -109,12 +121,12 @@
      * Updates the set of [Page]s owned by this manager when a new Page's dimensions are loaded.
      * Dimensions are the minimum data required to instantiate a page.
      */
-    fun onPageSizeReceived(
+    fun addPage(
         pageNum: Int,
         size: Point,
-        isVisible: Boolean,
         currentZoomLevel: Float,
-        isFlinging: Boolean
+        stablePosition: Boolean,
+        viewArea: Rect? = null
     ) {
         if (pages.contains(pageNum)) return
         val page =
@@ -128,7 +140,12 @@
                     onPageUpdate = { _invalidationSignalFlow.tryEmit(Unit) },
                     onPageTextReady = { pageNumber -> _pageTextReadyFlow.tryEmit(pageNumber) }
                 )
-                .apply { if (isVisible) updateState(currentZoomLevel, isFlinging) }
+                .apply {
+                    // If the page is visible, let it know
+                    if (viewArea != null) {
+                        setVisible(currentZoomLevel, viewArea, stablePosition)
+                    }
+                }
         pages.put(pageNum, page)
     }
 
@@ -151,7 +168,7 @@
      * Sets all [Page]s owned by this manager to invisible, i.e. to reduce memory when the host
      * [PdfView] is not in an interactive state.
      */
-    fun onDetached() {
+    fun cleanup() {
         for (page in pages.valueIterator()) {
             page.setInvisible()
         }
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
index 0c1973b..8885cb3 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfView.kt
@@ -40,6 +40,7 @@
 import android.view.ScaleGestureDetector
 import android.view.View
 import androidx.annotation.CallSuper
+import androidx.annotation.MainThread
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
 import androidx.core.graphics.toRectF
@@ -105,9 +106,9 @@
         set(value) {
             checkMainThread()
             value?.let {
-                val reset = field != null && field?.uri != value.uri
+                if (field == value) return
                 field = it
-                if (reset) reset()
+                reset()
                 onDocumentSet()
             }
         }
@@ -215,6 +216,7 @@
     private var awaitingFirstLayout: Boolean = true
     private var scrollPositionToRestore: PointF? = null
     private var zoomToRestore: Float? = null
+    @VisibleForTesting internal var isInitialZoomDone: Boolean = false
     /**
      * The width of the PdfView before the last layout change (e.g., before rotation). Used to
      * preserve the zoom level when the device is rotated.
@@ -231,6 +233,22 @@
     /** Whether we are in a fling movement. This is used to detect the end of that movement */
     private var isFling = false
 
+    /**
+     * Returns true if neither zoom nor scroll are actively changing. Does not account for
+     * externally-driven changes in position (e.g. a animating scrollY or zoom)
+     */
+    private val positionIsStable: Boolean
+        get() {
+            val zoomIsChanging = gestureTracker.matches(GestureTracker.Gesture.ZOOM)
+            val scrollIsChanging =
+                gestureTracker.matches(
+                    GestureTracker.Gesture.DRAG,
+                    GestureTracker.Gesture.DRAG_X,
+                    GestureTracker.Gesture.DRAG_Y
+                ) || isFling
+            return !zoomIsChanging && !scrollIsChanging
+        }
+
     // To avoid allocations during drawing
     private val visibleAreaRect = Rect()
 
@@ -250,9 +268,6 @@
     @VisibleForTesting
     internal var isTouchExplorationEnabled: Boolean =
         Accessibility.get().isTouchExplorationEnabled(context)
-        set(value) {
-            field = value
-        }
 
     private var selectionStateManager: SelectionStateManager? = null
     private val selectionRenderer = SelectionRenderer(context)
@@ -514,13 +529,14 @@
         super.onDetachedFromWindow()
         stopCollectingData()
         awaitingFirstLayout = true
-        pageManager?.onDetached()
+        pageManager?.cleanup()
     }
 
     override fun onSaveInstanceState(): Parcelable? {
         val superState = super.onSaveInstanceState()
         val state = PdfViewSavedState(superState)
         state.zoom = zoom
+        state.isInitialZoomDone = isInitialZoomDone
         state.viewWidth = width
         state.contentCenterX = toContentX(viewportWidth.toFloat() / 2f)
         state.contentCenterY = toContentY(viewportHeight.toFloat() / 2f)
@@ -553,11 +569,11 @@
             postInvalidateOnAnimation()
         } else if (isFling) {
             isFling = false
-            // Once the fling has ended, prompt the page manager to start fetching data for pages
-            // that we don't fetch during a fling
-            pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
             // We hide the action mode during a fling, so reveal it when the fling is over
             updateSelectionActionModeVisibility()
+            // Once the fling has ended, prompt the page manager to start fetching data for pages
+            // that we don't fetch during a fling
+            maybeUpdatePageVisibility()
         }
     }
 
@@ -605,7 +621,8 @@
         }
     }
 
-    private fun getDefaultZoom(): Float {
+    @VisibleForTesting
+    internal fun getDefaultZoom(): Float {
         if (contentWidth == 0 || viewportWidth == 0) return DEFAULT_INIT_ZOOM
         val widthZoom = viewportWidth.toFloat() / contentWidth
         return MathUtils.clamp(widthZoom, minZoom, maxZoom)
@@ -649,6 +666,7 @@
             scrollPositionToRestore = positionToRestore
             zoomToRestore = localStateToRestore.zoom
             oldWidth = localStateToRestore.viewWidth
+            isInitialZoomDone = localStateToRestore.isInitialZoomDone
         } else {
             scrollToRestoredPosition(positionToRestore, localStateToRestore.zoom)
         }
@@ -671,6 +689,7 @@
      * Launches a tree of coroutines to collect data from helper classes while we're attached to a
      * visible window
      */
+    @MainThread
     private fun startCollectingData() {
         val mainScope =
             CoroutineScope(HandlerCompat.createAsync(handler.looper).asCoroutineDispatcher())
@@ -684,7 +703,17 @@
                     launch {
                         manager.dimensions.collect { onPageDimensionsReceived(it.first, it.second) }
                     }
-                    launch { manager.visiblePages.collect { onVisiblePagesChanged() } }
+                    launch { manager.visiblePages.collect { maybeUpdatePageVisibility() } }
+                }
+            // Don't let two copies of this run concurrently
+            val visiblePagesToJoin = visiblePagesCollector?.apply { cancel() }
+            visiblePagesCollector =
+                mainScope.launch(start = CoroutineStart.UNDISPATCHED) {
+                    manager.visiblePages.collect {
+                        // Prevent 2 copies from running concurrently
+                        visiblePagesToJoin?.join()
+                        maybeUpdatePageVisibility()
+                    }
                 }
         }
         pageManager?.let { manager ->
@@ -821,13 +850,12 @@
         onViewportChanged()
         // Don't fetch new Bitmaps while the user is actively zooming, to avoid jank and rendering
         // churn
-        if (!gestureTracker.matches(GestureTracker.Gesture.ZOOM)) {
-            pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
-        }
+        if (positionIsStable) maybeUpdatePageVisibility()
     }
 
     private fun onViewportChanged() {
         pageLayoutManager?.onViewportChanged(scrollY, height, zoom)
+        if (positionIsStable) maybeUpdatePageVisibility()
         accessibilityPageHelper?.invalidateRoot()
         updateSelectionActionModeVisibility()
     }
@@ -886,18 +914,11 @@
         return RectF(viewport).intersects(leftEdge, topEdge, rightEdge, bottomEdge)
     }
 
-    /**
-     * Invoked by gesture handlers to let this view know that its position has stabilized, i.e. it's
-     * not actively changing due to user input
-     */
-    internal fun onStableZoom() {
-        pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
-    }
-
     private fun reset() {
         // Stop any in progress fling when we open a new document
         scroller.forceFinished(true)
         scrollTo(0, 0)
+        pageManager?.cleanup()
         zoom = DEFAULT_INIT_ZOOM
         pageManager = null
         pageLayoutManager = null
@@ -905,20 +926,22 @@
         stopCollectingData()
     }
 
-    /** React to a change in visible pages (load new pages and clean up old ones) */
-    private fun onVisiblePagesChanged() {
-        pageManager?.maybeUpdatePageState(visiblePages, zoom, isFling)
+    private fun maybeUpdatePageVisibility() {
+        val visiblePageAreas =
+            pageLayoutManager?.getVisiblePageAreas(visiblePages, getVisibleAreaInContentCoords())
+                ?: return
+        pageManager?.updatePageVisibilities(visiblePageAreas, zoom, positionIsStable)
     }
 
     /** React to a page's dimensions being made available */
     private fun onPageDimensionsReceived(pageNum: Int, size: Point) {
-        pageManager?.onPageSizeReceived(
-            pageNum,
-            size,
-            visiblePages.contains(pageNum),
-            zoom,
-            isFling
-        )
+        val pageLocation =
+            if (visiblePages.contains(pageNum)) {
+                pageLayoutManager?.getPageLocation(pageNum, getVisibleAreaInContentCoords())
+            } else {
+                null
+            }
+        pageManager?.addPage(pageNum, size, zoom, isFling, pageLocation)
         // Learning the dimensions of a page can change our understanding of the content that's in
         // the viewport
         pageLayoutManager?.onViewportChanged(scrollY, height, zoom)
@@ -927,7 +950,10 @@
         // centering if it's needed. It doesn't override any restored state because we're scrolling
         // to the current scroll position.
         if (pageNum == 0) {
-            this.zoom = getDefaultZoom()
+            if (!isInitialZoomDone) {
+                this.zoom = getDefaultZoom()
+                isInitialZoomDone = true
+            }
             scrollTo(scrollX, scrollY)
         }
 
@@ -1175,7 +1201,9 @@
         }
 
         override fun onGestureEnd(gesture: GestureTracker.Gesture?) {
-            if (gesture == GestureTracker.Gesture.ZOOM) onStableZoom()
+            // Update page visibility after scroll / zoom gestures end, because we avoid fetching
+            // certain data while those gestures are in progress
+            if (gesture in ZOOM_OR_SCROLL_GESTURES) maybeUpdatePageVisibility()
             totalX = 0f
             totalY = 0f
             straightenCurrentVerticalScroll = true
@@ -1383,6 +1411,14 @@
 
         private const val DEFAULT_PAGE_PREFETCH_RADIUS: Int = 2
 
+        private val ZOOM_OR_SCROLL_GESTURES =
+            setOf(
+                GestureTracker.Gesture.ZOOM,
+                GestureTracker.Gesture.DRAG,
+                GestureTracker.Gesture.DRAG_X,
+                GestureTracker.Gesture.DRAG_Y
+            )
+
         private fun checkMainThread() {
             check(Looper.myLooper() == Looper.getMainLooper()) {
                 "Property must be set on the main thread"
diff --git a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfViewSavedState.kt b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfViewSavedState.kt
index c0c5047..dd0ab91 100644
--- a/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfViewSavedState.kt
+++ b/pdf/pdf-viewer/src/main/kotlin/androidx/pdf/view/PdfViewSavedState.kt
@@ -30,6 +30,7 @@
     var zoom: Float = 1F
     var documentUri: Uri? = null
     var paginationModel: PaginationModel? = null
+    var isInitialZoomDone: Boolean = false
     /**
      * The width of the PdfView before the last layout change (e.g., before rotation). Used to
      * preserve the zoom level when the device is rotated.
diff --git a/pdf/pdf-viewer/src/main/res/values-af/strings.xml b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
index faf7bd3..907338a 100644
--- a/pdf/pdf-viewer/src/main/res/values-af/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Bladsy is vir die PDF-dokument gebreek"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Onvoldoende data om die PDF-dokument te verwerk"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Kan nie PDF-lêer oopmaak nie"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Inhoud gekopieer vanaf PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-am/strings.xml b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
index 2c973fa..d518661 100644
--- a/pdf/pdf-viewer/src/main/res/values-am/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"ለPDF ሰነዱ ገፅ ተበላሽቷል"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ሰነዱን ለማሰናዳት በቂ ያልሆነ ውሂብ"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ፋይል መክፈት አይቻልም"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"ይዘት ከPDF ተቀድቷል"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
index 1958e32..c2b3ec6 100644
--- a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"‏تعذّر تحميل صفحة من مستند PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"‏البيانات غير كافية لمعالجة مستند PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"‏يتعذّر فتح ملف PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"‏تم نسخ المحتوى من ملف PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-az/strings.xml b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
index 4f4045e..65132fe 100644
--- a/pdf/pdf-viewer/src/main/res/values-az/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF sənədi üçün səhifədə xəta var"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF sənədini emal etmək üçün kifayət qədər data yoxdur"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF faylını açmaq olmur"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Kontent PDF-dən kopiyalanıb"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
index 156e778..24b8a40 100644
--- a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Neispravna stranica za PDF dokument"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nedovoljno podataka za obradu PDF dokumenta"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Otvaranje PDF fajla nije uspelo"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Sadržaj je kopiran iz PDF-a"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-be/strings.xml b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
index e1a2a77..5f6ad1d 100644
--- a/pdf/pdf-viewer/src/main/res/values-be/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Старонка дакумента PDF пашкоджана"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Не хапае даных для апрацоўкі дакумента PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Не ўдаецца адкрыць файл PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Змесціва скапіравана з PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
index ba05b00..614d295 100644
--- a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"поле за парола"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"неправилна парола"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Грешна парола. Опитайте отново."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> от <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"Процент на промяна на мащаба: <xliff:g id="FIRST">%1$d</xliff:g>"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Към страница <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"начало на избраното"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"край на избраното"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"страници <xliff:g id="FIRST">%1$d</xliff:g> до <xliff:g id="LAST">%2$d</xliff:g> от <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Изображение: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Търсете във файла"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Невалидна страница в PDF документа"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Няма достатъчно данни за обработването на PDF документа"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF файлът не може да се отвори"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Съдържанието е копирано от PDF файла"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
index e617105..81012b0 100644
--- a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"পিডিএফ ডকুমেন্টের ক্ষেত্রে পৃষ্ঠা ভেঙে গেছে"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"পিডিএফ ডকুমেন্ট প্রসেস করার জন্য যথেষ্ট ডেটা নেই"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ফাইল খোলা যাচ্ছে না"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"পিডিএফ থেকে কন্টেন্ট কপি করা হয়েছে"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
index a90e957..80927bf 100644
--- a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"polje za lozinku"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"pogrešna lozinka"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Pogrešna lozinka Ponovni pokušaj."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. stranica od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zumiranje <xliff:g id="FIRST">%1$d</xliff:g> posto"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Odlazak na <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. stranicu"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Stranica je prelomljena za PDF dokument"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nema dovoljno podataka za obradu PDF dokumenta"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Nije moguće otvoriti PDF fajl"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Sadržaj je kopiran iz PDF-a"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
index 5f52251..a4f2ed0 100644
--- a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"camp de contrasenya"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasenya incorrecta"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Contrasenya incorrecta. Torna-ho a provar."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pàgina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Ves a la pàgina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"La pàgina no funciona per al document PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Les dades són insuficients per processar el document PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"No es pot obrir el fitxer PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Contingut copiat del PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
index d521d11..1d94a04 100644
--- a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Dokument PDF obsahuje poškozenou stránku"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nedostatek dat ke zpracování dokumentu PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Soubor PDF se nepodařilo otevřít"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Obsah byl zkopírován ze souboru PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-da/strings.xml b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
index 012a1a5..16677bf 100644
--- a/pdf/pdf-viewer/src/main/res/values-da/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"felt til adgangskode"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"adgangskoden er forkert"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Forkert adgangskode. Prøv igen."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> af <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"start på markering"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"slut på markering"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"side <xliff:g id="FIRST">%1$d</xliff:g> til <xliff:g id="LAST">%2$d</xliff:g> af <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Billede: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Søg i fil"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Siden er ødelagt for PDF-dokumentet"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Der er ikke nok data til at behandle PDF-dokumentet"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF-filen kan ikke åbnes"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Indholdet blev kopieret fra PDF-filen"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-de/strings.xml b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
index 3732805..bc94866 100644
--- a/pdf/pdf-viewer/src/main/res/values-de/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"Passwortfeld"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"Falsches Passwort"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Falsches Passwort. Versuch es nochmal."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Seite <xliff:g id="PAGE">%1$d</xliff:g> von <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"Zoom: <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Gehe zu Seite <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"Beginn der Auswahl"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"Ende der Auswahl"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"Seiten <xliff:g id="FIRST">%1$d</xliff:g> bis <xliff:g id="LAST">%2$d</xliff:g> von <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Bild: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"In Datei suchen"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Seite für PDF-Dokument ist fehlerhaft"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Keine ausreichenden Daten, um das PDF-Dokument zu verarbeiten"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF‑Datei kann nicht geöffnet werden"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Inhalt aus PDF kopiert"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-el/strings.xml b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
index bfef9c9..d34708d5 100644
--- a/pdf/pdf-viewer/src/main/res/values-el/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Δεν ήταν δυνατή η φόρτωση του εγγράφου PDF από τη σελίδα"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Μη επαρκή δεδομένα για την επεξεργασία του εγγράφου PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Δεν είναι δυνατό το άνοιγμα του αρχείου PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Το περιεχόμενο αντιγράφηκε από το PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
index 37aa01f..5b49160 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"password field"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Wrong password. Try again."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pages <xliff:g id="FIRST">%1$d</xliff:g> to <xliff:g id="LAST">%2$d</xliff:g> of <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Image: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Find in file"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Page broken for the PDF document"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Insufficient data for processing the PDF document"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Can\'t open PDF file"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Content copied from PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
index 37aa01f..5b49160 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"password field"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Wrong password. Try again."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pages <xliff:g id="FIRST">%1$d</xliff:g> to <xliff:g id="LAST">%2$d</xliff:g> of <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Image: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Find in file"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Page broken for the PDF document"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Insufficient data for processing the PDF document"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Can\'t open PDF file"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Content copied from PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
index 37aa01f..5b49160 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"password field"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"password incorrect"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Wrong password. Try again."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> of <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> per cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Go to page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Phone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"selection start"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"selection end"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pages <xliff:g id="FIRST">%1$d</xliff:g> to <xliff:g id="LAST">%2$d</xliff:g> of <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Image: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Find in file"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Page broken for the PDF document"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Insufficient data for processing the PDF document"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Can\'t open PDF file"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Content copied from PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
index 38a7d86f..1fbf379 100644
--- a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"La página no funciona para el documento PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"No hay datos suficientes para procesar el documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"No se puede abrir el archivo PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Se copió el contenido del PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-es/strings.xml b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
index 54e909e..9d335dd 100644
--- a/pdf/pdf-viewer/src/main/res/values-es/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"campo de contraseña"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"contraseña incorrecta"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Contraseña incorrecta. Inténtalo de nuevo."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> por ciento"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Ir a la página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inicio de la selección"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"final de la selección"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"páginas <xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> de <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Imagen: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Buscar en el archivo"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"La página no funciona para el documento PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Datos insuficientes para procesar el documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"No se puede abrir el archivo PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Contenido copiado del PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-et/strings.xml b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
index 7bdf417..4d52a6d 100644
--- a/pdf/pdf-viewer/src/main/res/values-et/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"parooliväli"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"parool on vale"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Vale parool. Proovige uuesti."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"lk <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"suum <xliff:g id="FIRST">%1$d</xliff:g> protsenti"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Mine lehele <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"valiku algus"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"valiku lõpp"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"lk <xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>-st"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Pilt: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Otsige failist"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Rikutud leht PDF-dokumendis"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF-dokumendi töötlemiseks pole piisavalt andmeid"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF-faili ei saa avada"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Sisu kopeeritud PDF-ist"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
index 48c22ae..163a362 100644
--- a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"pasahitzaren eremua"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"pasahitza okerra da"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Pasahitza ez da zuzena. Saiatu berriro."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g> orritatik <xliff:g id="PAGE">%1$d</xliff:g>garrena"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zooma ehuneko <xliff:g id="FIRST">%1$d</xliff:g>"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Joan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. orrira"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefono-zenbakia: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"hautapenaren hasiera"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"hautapenaren amaiera"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"<xliff:g id="FIRST">%1$d</xliff:g> eta <xliff:g id="LAST">%2$d</xliff:g> bitarteko orriak, guztira <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Irudia: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Bilatu fitxategia"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF dokumentuaren orria hondatuta dago"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Ez dago behar adina daturik PDF dokumentua prozesatzeko"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Ezin da ireki PDF fitxategia"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDFtik kopiatutako edukia"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
index c741e2c..e957a49 100644
--- a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"‏صفحه سند PDF خراب است"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"‏داده‌ها برای پردازش سند PDF کافی نیست"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"‏فایل PDF باز نشد"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"‏محتوای کپی‌شده از PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
index 53cc957..1be8815 100644
--- a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF-dokumenttiin liittyvä sivu on rikki"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Riittämätön data PDF-dokumentin käsittelyyn"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF-tiedostoa ei voi avata"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Sisältö kopioitu PDF-tiedostosta"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
index ccd0b38..cf9eeb2 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"champ du mot de passe"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Mot de passe incorrect. Réessayez."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Numéro de téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pages <xliff:g id="FIRST">%1$d</xliff:g> à <xliff:g id="LAST">%2$d</xliff:g> sur <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Image : <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Trouver dans fichier"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Page brisée pour le document PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Données insuffisantes pour le traitement du document PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Impossible d\'ouvrir le fichier PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Contenu copié à partir d\'un PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
index 05c1ad3..4c61f48f 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"champ de mot de passe"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"mot de passe incorrect"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Mot de passe incorrect. Réessayez."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"page <xliff:g id="PAGE">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom : <xliff:g id="FIRST">%1$d</xliff:g> pour cent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Accéder à la page <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Téléphone : <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"début de la sélection"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin de la sélection"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pages <xliff:g id="FIRST">%1$d</xliff:g> à <xliff:g id="LAST">%2$d</xliff:g> sur <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Image : <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Rechercher dans fichier"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Page non fonctionnelle pour le document PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Données insuffisantes pour le traitement du document PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Impossible d\'ouvrir le fichier PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Contenu copié depuis un PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
index b85aea9..7cbf622 100644
--- a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"campo do contrasinal"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"contrasinal incorrecto"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"O contrasinal é incorrecto. Téntao de novo."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"páxina <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom ao <xliff:g id="FIRST">%1$d</xliff:g> por cento"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Vai á páxina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Teléfono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inicio da selección"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fin da selección"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"páxinas da <xliff:g id="FIRST">%1$d</xliff:g> á <xliff:g id="LAST">%2$d</xliff:g> dun total de <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Imaxe: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Busca no ficheiro"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Non funciona a páxina para o documento PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Os datos non son suficientes para procesar o documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Non se puido abrir o PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Copiouse o contido desde o PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
index a06a2b3..ade2e21 100644
--- a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF દસ્તાવેજ માટે પેજ લોડ થઈ રહ્યું નથી"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF દસ્તાવેજ પર પ્રક્રિયા કરવા માટે પર્યાપ્ત ડેટા નથી"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ફાઇલ ખોલી શકાતી નથી"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDFમાંથી કન્ટેન્ટ કૉપિ કર્યું"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
index 0b612cc..00660b7 100644
--- a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"polje zaporke"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"zaporka nije točna"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Pogrešna zaporka. Pokušajte ponovo."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"stranica <xliff:g id="PAGE">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zumiranje <xliff:g id="FIRST">%1$d</xliff:g> posto"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Idite na stranicu <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefonski broj: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"početak odabira"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"završetak odabira"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"stranice od <xliff:g id="FIRST">%1$d</xliff:g> do <xliff:g id="LAST">%2$d</xliff:g> od ukupno <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Slika: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Pronađi u datoteci"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Stranica je raščlanjena za PDF dokument"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nema dovoljno podataka za obradu PDF dokumenta"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF datoteka ne može se otvoriti"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Sadržaj kopiran iz PDF-a"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
index 39d0f1e..71164e3 100644
--- a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"jelszómező"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"helytelen jelszó"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Helytelen jelszó. Próbálkozzon újra."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g> / <xliff:g id="PAGE">%1$d</xliff:g>."</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>."</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="PAGE">%1$d</xliff:g>. oldal"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> százalékos nagyítás"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Ugrás erre az oldalra: <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"kijelölés kezdete"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"kijelölés vége"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="TOTAL">%3$d</xliff:g> / <xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>."</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="TOTAL">%3$d</xliff:g>/<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>."</string>
     <string name="desc_page_range" msgid="5286496438609641577">"<xliff:g id="TOTAL">%3$d</xliff:g>/<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>. oldal"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Kép: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Keresés a fájlban"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Az oldal nem tölt be a PDF-dokumentumban"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nem áll rendelkezésre elegendő adat a PDF-dokumentum feldolgozásához"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Nem sikerült megnyitni a PDF-fájlt"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Tartalom másolva PDF-ből"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
index 2b64b83..be6da93 100644
--- a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"գաղտնաբառի դաշտ"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"գաղտնաբառը սխալ է"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Գաղտնաբառը սխալ է։ Նորից փորձեք։"</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Էջ <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"մասշտաբ՝ <xliff:g id="FIRST">%1$d</xliff:g> տոկոս"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Անցեք <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> էջ"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Հեռախոս՝ <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"ընտրված տեքստի սկիզբ"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"ընտրված տեքստի վերջ"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"էջ <xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>՝ <xliff:g id="TOTAL">%3$d</xliff:g>-ից"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Պատկեր՝ <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Գտեք ֆայլում"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF փաստաթղթի էջը վնասված է"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Ոչ բավարար տվյալներ PDF փաստաթղթի մշակման համար"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Չհաջողվեց բացել PDF ֆայլը"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF ֆայլից պատճենված բովանդակություն"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-in/strings.xml b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
index b10c88d..9c3fa04 100644
--- a/pdf/pdf-viewer/src/main/res/values-in/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"kolom sandi"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"sandi salah"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Sandi salah. Coba lagi."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"halaman <xliff:g id="PAGE">%1$d</xliff:g> dari <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> persen"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Buka halaman <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Halaman dokumen PDF rusak"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Data tidak cukup untuk memproses dokumen PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Tidak dapat membuka file PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Konten disalin dari PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-is/strings.xml b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
index 3a9d53d3..0ab21f3 100644
--- a/pdf/pdf-viewer/src/main/res/values-is/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Síða í PDF-skjali er gölluð"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Ekki næg gögn fyrir úrvinnslu á PDF-skjali"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Ekki tókst að opna PDF-skrá"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Efni afritað úr PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-it/strings.xml b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
index 48da371..7412194 100644
--- a/pdf/pdf-viewer/src/main/res/values-it/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"campo password"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"password errata"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Password errata. Riprova."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> di <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Vai alla pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefono: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"inizio selezione"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fine selezione"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"pagine da <xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> di <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Immagine: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Trova nel file"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Pagina inaccessibile per il documento PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Dati insufficienti per l\'elaborazione del documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Impossibile aprire il file PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Contenuti copiati dal PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
index 294e58c..1383134 100644
--- a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"‏קישור מנותק בדף למסמך ה-PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"‏אין מספיק נתונים כדי לעבד את מסמך ה-PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"‏לא ניתן לפתוח את קובץ ה-PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"‏התוכן הועתק מקובץ PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
index 1684664..76ee961 100644
--- a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"パスワードを入力する項目です"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"パスワードが正しくありません"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"パスワードが正しくありません。もう一度お試しください。"</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> ページ"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ズーム <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> ページに移動します"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"電話番号: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選択範囲の最初"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選択範囲の最後"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g> ページ"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"画像: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"ファイル内を検索"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
index 4047aae..a2c32ee 100644
--- a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"құпия сөз өрісі"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"құпия сөз қате"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Құпия сөз қате. Қайталап көріңіз."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"Бет: <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g> пайызға масштабтау"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g>-бетке өтіңіз."</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"таңдалған мәтіннің басы"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"таңдалған мәтіннің соңы"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"Бет: <xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Сурет: <xliff:g id="ALT_TEXT">%1$s</xliff:g>."</string>
     <string name="hint_find" msgid="5385388836603550565">"Файлдан табу"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF құжатының беті бұзылған."</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF құжатын өңдеу үшін деректер жеткіліксіз."</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF файлын ашу мүмкін емес."</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF файлынан көшірілген контент"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-km/strings.xml b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
index 8192706..8dc92e4 100644
--- a/pdf/pdf-viewer/src/main/res/values-km/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"ទំព័រ​មិនដំណើរការ​សម្រាប់​ឯកសារ PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"មានទិន្នន័យ​មិនគ្រប់គ្រាន់​សម្រាប់​ដំណើរការ​ឯកសារ PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"មិនអាចបើកឯកសារ PDF បានទេ"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"បានចម្លងខ្លឹមសារពី PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
index a03105f..ccb316d 100644
--- a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF ಡಾಕ್ಯುಮೆಂಟ್‌ಗೆ ಸಂಬಂಧಿಸಿದ ಪುಟ ಮುರಿದಿದೆ"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ಡಾಕ್ಯುಮೆಂಟ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಕಷ್ಟು ಡೇಟಾ ಇಲ್ಲ"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ಫೈಲ್‌ ಅನ್ನು ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"ಕಂಟೆಂಟ್ ಅನ್ನು PDF ನಿಂದ ಕಾಪಿ ಮಾಡಲಾಗಿದೆ"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
index 3cfb9f1..b334d32 100644
--- a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"비밀번호 입력란"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"비밀번호가 잘못됨"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"잘못된 비밀번호입니다. 다시 시도하세요."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="TOTAL">%2$d</xliff:g>페이지 중 <xliff:g id="PAGE">%1$d</xliff:g>페이지"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"<xliff:g id="FIRST">%1$d</xliff:g>%% 확대/축소"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"<xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 페이지로 이동"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"전화번호: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"선택 영역 시작"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"선택 영역 끝"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"<xliff:g id="TOTAL">%3$d</xliff:g>페이지 중 <xliff:g id="FIRST">%1$d</xliff:g>~<xliff:g id="LAST">%2$d</xliff:g>페이지"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"이미지: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"파일에서 찾기"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF 문서의 페이지가 손상되었습니다."</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF 문서 처리를 위한 데이터가 부족합니다."</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF 파일을 열 수 없음"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF에서 복사된 콘텐츠"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
index c6efa08..9b96c97 100644
--- a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF документинин барагы бузук"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF документин иштетүү үчүн маалымат жетишсиз"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF файл ачылбай жатат"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Контент PDF\'тен көчүрүлдү"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
index dacf6fa..b737461 100644
--- a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"ໜ້າເສຍຫາຍສໍາລັບເອກະສານ PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"ຂໍ້ມູນບໍ່ພຽງພໍສໍາລັບການປະມວນຜົນເອກະສານ PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"ບໍ່ສາມາດເປີດໄຟລ໌ PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"ສໍາເນົາເນື້ອຫາຈາກ PDF ແລ້ວ"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
index 9a284fe..e260cf5 100644
--- a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Sugadintas PDF dokumento puslapis"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nepakanka duomenų PDF dokumentui apdoroti"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Nepavyksta atidaryti PDF failo"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Turinys nukopijuotas iš PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
index 3dce52e..7d455ea 100644
--- a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"paroles lauks"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"parole nav pareiza"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Nepareiza parole. Mēģiniet vēlreiz."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"<xliff:g id="PAGE">%1$d</xliff:g>. lapa no <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"tālummaiņa procentos ir <xliff:g id="FIRST">%1$d</xliff:g>"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Doties uz <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>. lapu"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Tālruņa numurs: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"atlases sākums"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"atlases beigas"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"<xliff:g id="FIRST">%1$d</xliff:g>.–<xliff:g id="LAST">%2$d</xliff:g>. lapa no <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Attēls: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Meklēt failā"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF dokumenta lapa ir bojāta"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nepietiekams datu apjoms, lai apstrādātu PDF dokumentu"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Nevar atvērt PDF failu."</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"No PDF faila kopēts saturs"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
index 1d569ea..5735451 100644
--- a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"поле за лозинка"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"лозинката е неточна"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Погрешна лозинка. Обидете се повторно."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"страница <xliff:g id="PAGE">%1$d</xliff:g> од <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"зумирајте <xliff:g id="FIRST">%1$d</xliff:g> проценти"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Одете на страницата <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Телефон: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"почеток на изборот"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"крај на изборот"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"од страница <xliff:g id="FIRST">%1$d</xliff:g> до <xliff:g id="LAST">%2$d</xliff:g> од <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Слика: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Најдете во датотека"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Страницата не може да го вчита PDF-документот"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Недоволно податоци за обработка на PDF-документот"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Не може да се отвори PDF-датотеката"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Содржините се копирани од PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
index 930c2b7..4198e49 100644
--- a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF баримт бичгийн хуудас эвдэрсэн"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF баримт бичгийг боловсруулахад өгөгдөл хангалтгүй байна"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF файлыг нээх боломжгүй"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF-с контент хуулсан"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
index 41b2446..01afbd7 100644
--- a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"पीडीएफ दस्तऐवजासाठी पेज खंडित झाले आहे"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF दस्तऐवजावर प्रक्रिया करण्यासाठी डेटा पुरेसा नाही"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF फाइल उघडू शकत नाही"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"आशय PDF वरून कॉपी केला आहे"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-my/strings.xml b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
index f7705fe..4a00bad 100644
--- a/pdf/pdf-viewer/src/main/res/values-my/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF မှတ်တမ်းအတွက် စာမျက်နှာ ပျက်နေသည်"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF မှတ်တမ်း လုပ်ဆောင်ရန်အတွက် ဒေတာ မလုံလောက်ပါ"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ဖိုင်ကို ဖွင့်၍မရပါ"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF မှ မိတ္တူကူးထားသည့် အကြောင်းအရာ"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
index fd76435..bd09342 100644
--- a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"passordfelt"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"feil passord"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Feil passord. Prøv på nytt."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"side <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> prosent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Gå til side <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"starten av utvalget"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"slutten av utvalget"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"side <xliff:g id="FIRST">%1$d</xliff:g> til <xliff:g id="LAST">%2$d</xliff:g> av <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Bilde: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Finn i filen"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Siden er ødelagt for PDF-dokumentet"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Det er utilstrekkelige data for behandling av PDF-dokumentet"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Kan ikke åpne PDF-filen"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Innholdet er kopiert fra en PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
index ca0437a..4d6929b 100644
--- a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF डकुमेन्टको पेज लोड गर्न सकिएन"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF डकुमेन्ट प्रोसेस गर्न पर्याप्त जानकारी छैन"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF फाइल खोल्न सकिएन"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF बाट कपी गरिएको सामग्री"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
index 2f98f70..0b6fbe0 100644
--- a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"wachtwoordveld"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"wachtwoord is onjuist"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Onjuist wachtwoord. Probeer het opnieuw."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"pagina <xliff:g id="PAGE">%1$d</xliff:g> van <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Ga naar pagina <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Pagina van het pdf-document kan niet worden geladen"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Onvoldoende gegevens om het pdf-document te verwerken"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Kan pdf-bestand niet openen"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Content gekopieerd uit pdf"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-or/strings.xml b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
index 8a0582a..e6808dc 100644
--- a/pdf/pdf-viewer/src/main/res/values-or/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF ଡକ୍ୟୁମେଣ୍ଟ ପାଇଁ ପୃଷ୍ଠା ବିଭାଜିତ ହୋଇଛି"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ଡକ୍ୟୁମେଣ୍ଟ ପ୍ରକ୍ରିୟାକରଣ ପାଇଁ ପର୍ଯ୍ୟାପ୍ତ ଡାଟା ନାହିଁ"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ଫାଇଲକୁ ଖୋଲାଯାଇପାରିବ ନାହିଁ"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDFରୁ ବିଷୟବସ୍ତୁ କପି କରାଯାଇଛି"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
index ff925a3..46bfbf6 100644
--- a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF ਦਸਤਾਵੇਜ਼ ਲਈ ਪੰਨਾ ਲੋਡ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ਦਸਤਾਵੇਜ਼ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਕਰਨ ਲਈ ਲੋੜੀਂਦਾ ਡਾਟਾ ਨਹੀਂ ਹੈ"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ਫ਼ਾਈਲ ਖੋਲ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕਦੀ"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF ਤੋਂ ਕਾਪੀ ਕੀਤੀ ਗਈ ਸਮੱਗਰੀ"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
index c06a100..bcd1878 100644
--- a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"pole hasła"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"nieprawidłowe hasło"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Błędne hasło. Spróbuj ponownie."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"strona <xliff:g id="PAGE">%1$d</xliff:g> z <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"powiększenie <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Idź do strony <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
index 87937e2..69988f4 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Página do documento PDF corrompida"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Dados insuficientes para processamento do documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Não é possível abrir o arquivo PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Conteúdo copiado do PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
index d9db7c2..9b603b9 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"campo palavra-passe"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"palavra-passe incorreta"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Palavra-passe incorreta. Tente novamente."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"página <xliff:g id="PAGE">%1$d</xliff:g> de <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zoom a <xliff:g id="FIRST">%1$d</xliff:g> por cento"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Ir para a página <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefone: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"início da seleção"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"fim da seleção"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"páginas <xliff:g id="FIRST">%1$d</xliff:g> a <xliff:g id="LAST">%2$d</xliff:g> de <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Imagem: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Procure no ficheiro"</string>
diff --git a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
index 87937e2..69988f4 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Página do documento PDF corrompida"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Dados insuficientes para processamento do documento PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Não é possível abrir o arquivo PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Conteúdo copiado do PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
index 1d04a93..96bb18b 100644
--- a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Pagină deteriorată pentru documentul PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Date insuficiente pentru procesarea documentului PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Nu se poate deschide fișierul PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Conținutul a fost copiat din PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
index c4670b90..7776686 100644
--- a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Страница документа PDF повреждена"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Недостаточно данных для обработки документа PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Не удается открыть PDF-файл."</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Скопировано из PDF-файла"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-si/strings.xml b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
index d92f11a..247104e 100644
--- a/pdf/pdf-viewer/src/main/res/values-si/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF ලේඛනය සඳහා පිටුව හානි වී ඇත"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ලේඛනය සැකසීම සඳහා ප්‍රමාණවත් දත්ත නොමැත"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ගොනුව විවෘත කළ නොහැක"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF වෙතින් පිටපත් කළ අන්තර්ගතය"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
index dcf8c81..f0fa238 100644
--- a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Stránka sa v dokumente vo formáte PDF nedá načítať"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"V dokumente vo formáte PDF nie je dostatok údajov na spracovanie"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Súbor PDF sa nepodarilo otvoriť"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Obsah bol skopírovaný zo súboru PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
index b57be5b..9c2488a 100644
--- a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"polje za geslo"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"napačno geslo"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Napačno geslo. Poskusite znova."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"stran <xliff:g id="PAGE">%1$d</xliff:g> od <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"povečava <xliff:g id="FIRST">%1$d</xliff:g> %%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Pojdi na stran <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"začetek izbire"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"konec izbire"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"strani <xliff:g id="FIRST">%1$d</xliff:g> do <xliff:g id="LAST">%2$d</xliff:g> od <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Slika: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Iskanje v datoteki"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Strani iz dokumenta PDF ni mogoče prikazati"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Nezadostni podatki za obdelavo dokumenta PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Datoteke PDF ni mogoče odpreti"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Vsebina je kopirana iz datoteke PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
index 517bdae..8a47505 100644
--- a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Faqe e dëmtuar për dokumentin PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Të dhëna të pamjaftueshme për përpunimin e dokumentit PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Skedari PDF nuk mund të hapet"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Përmbajtja e kopjuar nga PDF-ja"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
index 305c103..0d69d5e 100644
--- a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Неисправна страница за PDF документ"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Недовољно података за обраду PDF документа"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Отварање PDF фајла није успело"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Садржај је копиран из PDF-а"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
index 53838ff..abcca45 100644
--- a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"lösenordsfält"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"felaktigt lösenord"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Fel lösenord. Försök igen."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sida <xliff:g id="PAGE">%1$d</xliff:g> av <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"zooma <xliff:g id="FIRST">%1$d</xliff:g> procent"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Öppna sidan <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefonnummer: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"textmarkeringens början"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"textmarkeringens slut"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>–<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"sidorna <xliff:g id="FIRST">%1$d</xliff:g> till <xliff:g id="LAST">%2$d</xliff:g> av <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Bild: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Hitta i filen"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Det gick inte att läsa in en sida i PDF-dokumentet"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Otillräcklig data för att behandla PDF-dokumentet"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Det går inte att öppna PDF-filen"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Innehåll har kopierats från PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
index 19d3afe..1d60764 100644
--- a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Ukurasa wa hati ya PDF una tatizo"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Hamna data ya kutosha kuchakata hati ya PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Imeshindwa kufungua faili ya PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Imenakili maudhui kutoka PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
index 3a526a2..0ac2405 100644
--- a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF ஆவணத்தை ஏற்ற முடியவில்லை"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF ஆவணத்தைச் செயலாக்குவதற்குப் போதுமான தரவு இல்லை"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ஃபைலைத் திறக்க முடியவில்லை"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDFல் இருந்து நகலெடுக்கப்பட்ட உள்ளடக்கம்"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-te/strings.xml b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
index 2c91b5c..ad559a5 100644
--- a/pdf/pdf-viewer/src/main/res/values-te/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF డాక్యుమెంట్‌కు సంబంధించి పేజీ బ్రేక్ అయింది"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF డాక్యుమెంట్‌ను ప్రాసెస్ చేయడానికి డేటా తగినంత లేదు"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF ఫైల్‌ను తెరవడం సాధ్యపడదు"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"కంటెంట్ PDF నుండి కాపీ అయింది"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-th/strings.xml b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
index 2f73d7c..d930711 100644
--- a/pdf/pdf-viewer/src/main/res/values-th/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"ช่องรหัสผ่าน"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"รหัสผ่านไม่ถูกต้อง"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"รหัสผ่านไม่ถูกต้อง โปรดลองอีกครั้ง"</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"หน้า <xliff:g id="PAGE">%1$d</xliff:g> จาก <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"ซูม <xliff:g id="FIRST">%1$d</xliff:g> เปอร์เซ็นต์"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"ไปที่หน้า <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"หมายเลขโทรศัพท์: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"เริ่มส่วนที่เลือก"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"สิ้นสุดส่วนที่เลือก"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"หน้า <xliff:g id="FIRST">%1$d</xliff:g> ถึง <xliff:g id="LAST">%2$d</xliff:g> จาก <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"รูปภาพ: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"ค้นหาในไฟล์"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"หน้าในเอกสาร PDF เสียหาย"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"ข้อมูลไม่เพียงพอสำหรับการประมวลผลเอกสาร PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"เปิดไฟล์ PDF ไม่ได้"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"เนื้อหาที่คัดลอกมาจาก PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
index 1d51aaa..de78569 100644
--- a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Sira ang page para sa PDF na dokumento"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Kulang ang data para maproseso ang PDF na dokumento"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Hindi mabuksan ang PDF file"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Nakopya ang content mula sa PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
index 14b1abc..de94f9c 100644
--- a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"şifre alanı"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"şifre yanlış"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Yanlış şifre. Tekrar deneyin."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"sayfa <xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"yakınlaştırma yüzdesi <xliff:g id="FIRST">%1$d</xliff:g>"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Şu sayfaya git <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Telefon: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"seçim başlangıcı"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"seçim sonu"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"sayfa <xliff:g id="FIRST">%1$d</xliff:g>-<xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Resim: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Dosyada bul"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF dokümanının sayfası bozuk"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF dokümanını işleyecek kadar yeterli veri yok"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF dosyası açılamıyor"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"PDF\'den kopyalanan içerik"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
index c622b57..cc835f2 100644
--- a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Сторінку документа PDF пошкоджено"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Недостатньо даних для обробки документа PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Не вдалося відкрити файл PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Контент скопійовано з PDF-файлу"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
index 6b542e8..14c25d6 100644
--- a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"‏‫PDF دستاویز کیلئے شکستہ صفحہ"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"‏‫PDF دستاویز پر کارروائی کرنے کیلئے ڈیٹا ناکافی ہے"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"‏‫PDF فائل کو کھولا نہیں جا سکتا"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"‏‫PDF سے کاپی کیا گیا مواد"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
index 0dfea8a..0b7c2cc 100644
--- a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF hujjat sahifasi yaroqsiz"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"PDF hujjatni qayta ishlash uchun kerakli axborotlar yetarli emas"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"PDF fayk ochilmadi"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Kontent PDF fayldan nusxalandi"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
index 76e2782..fc6c2b1 100644
--- a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"trường nhập mật khẩu"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"mật khẩu không chính xác"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"Sai mật khẩu. Hãy thử lại."</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"trang <xliff:g id="PAGE">%1$d</xliff:g> trong số <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"thu phóng <xliff:g id="FIRST">%1$d</xliff:g> phần trăm"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"Chuyển đến trang <xliff:g id="PAGE_NUMBER">%1$d</xliff:g>"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"Số điện thoại: <xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"đầu văn bản đã chọn"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"cuối văn bản đã chọn"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> – <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"các trang <xliff:g id="FIRST">%1$d</xliff:g> đến <xliff:g id="LAST">%2$d</xliff:g> trong số <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"Hình ảnh: <xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"Tìm trong tệp"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Tài liệu PDF này bị lỗi trang"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Không đủ dữ liệu để xử lý tài liệu PDF này"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Không mở được tệp PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Đã sao chép nội dung từ tệp PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
index 683dddd..9924fa2 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF 文档的页面已损坏"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"数据不足,无法处理 PDF 文档"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"无法打开 PDF 文件"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"从 PDF 复制的内容"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
index 6c6c835..016a712 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"密碼錯誤,請再試一次。"</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"電話:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"第 <xliff:g id="FIRST">%1$d</xliff:g> 至 <xliff:g id="LAST">%2$d</xliff:g> 頁 (共 <xliff:g id="TOTAL">%3$d</xliff:g> 頁)"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"圖片:<xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"在檔案中搜尋"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF 文件頁面已損毀"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"沒有足夠資料處理 PDF 文件"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"無法開啟 PDF 檔案"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"從 PDF 複製的內容"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
index bb54eca..f4337fd 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
@@ -25,7 +25,7 @@
     <string name="desc_password" msgid="6636473611443746739">"密碼欄位"</string>
     <string name="desc_password_incorrect" msgid="4718823067483963845">"密碼不正確"</string>
     <string name="desc_password_incorrect_message" msgid="4676206571020946870">"密碼錯誤,請再試一次。"</string>
-    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="label_page_single" msgid="456123685879261101">"<xliff:g id="PAGE">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="desc_page_single" msgid="8459583146661044094">"第 <xliff:g id="PAGE">%1$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%2$d</xliff:g> 頁"</string>
     <string name="desc_zoom" msgid="7318480946145947242">"縮放 <xliff:g id="FIRST">%1$d</xliff:g>%%"</string>
     <string name="desc_goto_link" msgid="2461368384824849714">"前往第 <xliff:g id="PAGE_NUMBER">%1$d</xliff:g> 頁"</string>
@@ -40,7 +40,7 @@
     <string name="desc_phone_link" msgid="4986414958429253135">"電話號碼:<xliff:g id="PHONE_NUMBER">%1$s</xliff:g>"</string>
     <string name="desc_selection_start" msgid="3249210022376857070">"選取開頭"</string>
     <string name="desc_selection_stop" msgid="2690168835536726898">"選取結尾"</string>
-    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g> / <xliff:g id="TOTAL">%3$d</xliff:g>"</string>
+    <string name="label_page_range" msgid="8290964180158460076">"<xliff:g id="FIRST">%1$d</xliff:g> - <xliff:g id="LAST">%2$d</xliff:g>/<xliff:g id="TOTAL">%3$d</xliff:g>"</string>
     <string name="desc_page_range" msgid="5286496438609641577">"第 <xliff:g id="FIRST">%1$d</xliff:g> 到 <xliff:g id="LAST">%2$d</xliff:g> 頁,共 <xliff:g id="TOTAL">%3$d</xliff:g> 頁"</string>
     <string name="desc_image_alt_text" msgid="7700601988820586333">"圖片:<xliff:g id="ALT_TEXT">%1$s</xliff:g>"</string>
     <string name="hint_find" msgid="5385388836603550565">"在檔案中搜尋"</string>
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"PDF 文件的頁面損毀"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"資料不足,無法處理 PDF 文件"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"無法開啟 PDF 檔案"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"已從 PDF 複製內容"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
index d5e0c57..59804ef 100644
--- a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
@@ -60,6 +60,5 @@
     <string name="page_broken" msgid="2968770793669433462">"Ikhasi eliphuliwe ledokhumenti ye-PDF"</string>
     <string name="needs_more_data" msgid="3520133467908240802">"Idatha enganele yokucubungula idokhumenti ye-PDF"</string>
     <string name="error_cannot_open_pdf" msgid="2361919778558145071">"Ayikwazi ukuvula ifayela le-PDF"</string>
-    <!-- no translation found for clipboard_label (8943155331324944981) -->
-    <skip />
+    <string name="clipboard_label" msgid="8943155331324944981">"Okuqukethwe kukopishwe ku-PDF"</string>
 </resources>
diff --git a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
index fc60503..048f51b 100644
--- a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
+++ b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/BitmapFetcherTest.kt
@@ -16,7 +16,9 @@
 
 package androidx.pdf.view
 
+import android.graphics.Bitmap
 import android.graphics.Point
+import android.graphics.Rect
 import androidx.pdf.PdfDocument
 import com.google.common.truth.Truth.assertThat
 import kotlin.math.roundToInt
@@ -48,6 +50,7 @@
 
     private val maxBitmapSizePx = Point(2048, 2048)
     private val pageSize = Point(512, 512)
+    private val fullPageViewArea = Rect(0, 0, pageSize.x, pageSize.y)
 
     private lateinit var bitmapFetcher: BitmapFetcher
     private lateinit var tileSizePx: Point
@@ -72,23 +75,23 @@
 
     @Test
     fun setInactive_cancelsWorkAndFreesBitmaps() {
-        bitmapFetcher.onScaleChanged(1.5f)
-        assertThat(bitmapFetcher.renderingJob?.isActive).isTrue()
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
+        assertThat(bitmapFetcher.fetchingWorkHandle?.isActive).isTrue()
 
         bitmapFetcher.isActive = false
-        assertThat(bitmapFetcher.renderingJob).isNull()
+        assertThat(bitmapFetcher.fetchingWorkHandle).isNull()
         assertThat(bitmapFetcher.pageContents).isNull()
     }
 
     @Test
-    fun setScale_rendersFullPageBitmap() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun lowScale_fullPageViewArea_fetchesFullPageBitmap() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         testDispatcher.scheduler.runCurrent()
 
         val pageBitmaps = bitmapFetcher.pageContents
         assertThat(pageBitmaps).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(pageBitmaps?.renderedScale).isEqualTo(1.5f)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(1.5f)
         pageBitmaps as FullPageBitmap // Make smartcast work nicely below
         assertThat(pageBitmaps.bitmap.width).isEqualTo((pageSize.x * 1.5f).roundToInt())
         assertThat(pageBitmaps.bitmap.height).isEqualTo((pageSize.y * 1.5f).roundToInt())
@@ -96,14 +99,33 @@
     }
 
     @Test
-    fun setScale_rendersTileBoard() {
-        bitmapFetcher.onScaleChanged(5.0f)
+    fun lowScale_partialPageViewArea_fetchesFullPageBitmap() {
+        // 1.5 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            1.5f,
+            viewArea = Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+
+        testDispatcher.scheduler.runCurrent()
+
+        val pageBitmaps = bitmapFetcher.pageContents
+        assertThat(pageBitmaps).isInstanceOf(FullPageBitmap::class.java)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(1.5f)
+        pageBitmaps as FullPageBitmap // Make smartcast work nicely below
+        assertThat(pageBitmaps.bitmap.width).isEqualTo((pageSize.x * 1.5f).roundToInt())
+        assertThat(pageBitmaps.bitmap.height).isEqualTo((pageSize.y * 1.5f).roundToInt())
+        assertThat(invalidationCounter).isEqualTo(1)
+    }
+
+    @Test
+    fun highScale_fullPageViewArea_fetchesTileBoard() {
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
 
         testDispatcher.scheduler.runCurrent()
 
         val pageBitmaps = bitmapFetcher.pageContents
         assertThat(pageBitmaps).isInstanceOf(TileBoard::class.java)
-        assertThat(pageBitmaps?.renderedScale).isEqualTo(5.0f)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(5.0f)
         pageBitmaps as TileBoard // Make smartcast work nicely below
 
         // Check the properties of an arbitrary full-size tile
@@ -123,21 +145,54 @@
         assertThat(row3Col3.offsetPx).isEqualTo(Point(tileSizePx.x * 3, tileSizePx.y * 3))
         assertThat(row3Col3.exactSizePx).isEqualTo(row3Col3Size)
 
+        for (tile in pageBitmaps.tiles) {
+            assertThat(tile.bitmap).isNotNull()
+        }
+
         // 1 invalidation for the low-res background, 1 for each tile * 16 tiles
         assertThat(invalidationCounter).isEqualTo(17)
     }
 
     @Test
-    fun setScale_toRenderedValue_noNewWork() {
+    fun highScale_partialPageViewArea_fetchesPartialTileBoard() {
+        // 1.5 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            viewArea = Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+
+        testDispatcher.scheduler.runCurrent()
+
+        val pageBitmaps = bitmapFetcher.pageContents
+        assertThat(pageBitmaps).isInstanceOf(TileBoard::class.java)
+        assertThat(pageBitmaps?.bitmapScale).isEqualTo(5.0f)
+        pageBitmaps as TileBoard // Make smartcast work nicely below
+        // This is all tiles in row >= 0 && col >= 0 (row 1 and col 1 are partially visible)
+        val expectedVisibleIndices = setOf(5, 6, 7, 9, 10, 11, 13, 14, 15)
+
+        for (tile in pageBitmaps.tiles) {
+            if (tile.index in expectedVisibleIndices) {
+                assertThat(tile.bitmap).isNotNull()
+            } else {
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+
+        // 1 invalidation for the low-res background, 1 for each visible tile * 9 visible tiles
+        assertThat(invalidationCounter).isEqualTo(10)
+    }
+
+    @Test
+    fun changeScale_toFetchedValue_noNewWork() {
         bitmapFetcher.isActive = true
 
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val firstBitmaps = bitmapFetcher.pageContents
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         // We shouldn't have started a new Job the second time onScaleChanged to the same value
-        assertThat(bitmapFetcher.renderingJob).isNull()
+        assertThat(bitmapFetcher.fetchingWorkHandle?.isActive).isFalse()
         // And we should still have the same bitmaps
         assertThat(bitmapFetcher.pageContents).isEqualTo(firstBitmaps)
         // 1 total invalidation
@@ -145,20 +200,20 @@
     }
 
     @Test
-    fun setScale_toRenderingValue_noNewWork() {
-        bitmapFetcher.onScaleChanged(1.5f)
-        val firstJob = bitmapFetcher.renderingJob
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_toFetchingValue_noNewWork() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
+        val firstJob = bitmapFetcher.fetchingWorkHandle
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
 
         // This should be the same Job we started the first time onScaleChanged
-        assertThat(bitmapFetcher.renderingJob).isEqualTo(firstJob)
+        assertThat(bitmapFetcher.fetchingWorkHandle).isEqualTo(firstJob)
         // 0 invalidations because we're still rendering
         assertThat(invalidationCounter).isEqualTo(0)
     }
 
     @Test
-    fun setScale_afterInactive_rendersNewBitmaps() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_afterInactive_fetchesNewBitmaps() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         assertThat(bitmapFetcher.pageContents).isNotNull()
         assertThat(invalidationCounter).isEqualTo(1)
@@ -167,47 +222,106 @@
         assertThat(bitmapFetcher.pageContents).isNull()
 
         bitmapFetcher.isActive = true
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         assertThat(bitmapFetcher.pageContents).isNotNull()
         assertThat(invalidationCounter).isEqualTo(2)
     }
 
     @Test
-    fun setScale_fromFullPage_toTiled() {
-        bitmapFetcher.onScaleChanged(1.5f)
+    fun changeScale_lowToHigh_fullPageToTiling() {
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val fullPageBitmap = bitmapFetcher.pageContents
         assertThat(fullPageBitmap).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(fullPageBitmap?.renderedScale).isEqualTo(1.5f)
+        assertThat(fullPageBitmap?.bitmapScale).isEqualTo(1.5f)
         assertThat(invalidationCounter).isEqualTo(1)
 
-        bitmapFetcher.onScaleChanged(5.0f)
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val tileBoard = bitmapFetcher.pageContents
         assertThat(tileBoard).isInstanceOf(TileBoard::class.java)
-        assertThat(tileBoard?.renderedScale).isEqualTo(5.0f)
+        assertThat(tileBoard?.bitmapScale).isEqualTo(5.0f)
         // 1 invalidation for the previous full page bitmap + 1 for the low res background
         // + (1 for each tile * 16 tiles)
         assertThat(invalidationCounter).isEqualTo(18)
     }
 
     @Test
-    fun setScale_fromTiled_toFullPage() {
-        bitmapFetcher.onScaleChanged(5.0f)
+    fun changeScale_highToLow_tilingToFullPage() {
+        bitmapFetcher.updateViewProperties(5.0f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val tileBoard = bitmapFetcher.pageContents
         assertThat(tileBoard).isInstanceOf(TileBoard::class.java)
-        assertThat(tileBoard?.renderedScale).isEqualTo(5.0f)
+        assertThat(tileBoard?.bitmapScale).isEqualTo(5.0f)
         // 1 invalidation for the low res background + (1 for each tile * 16 tiles)
         assertThat(invalidationCounter).isEqualTo(17)
 
-        bitmapFetcher.onScaleChanged(1.5f)
+        bitmapFetcher.updateViewProperties(1.5f, fullPageViewArea)
         testDispatcher.scheduler.runCurrent()
         val fullPageBitmap = bitmapFetcher.pageContents
         assertThat(fullPageBitmap).isInstanceOf(FullPageBitmap::class.java)
-        assertThat(fullPageBitmap?.renderedScale).isEqualTo(1.5f)
+        assertThat(fullPageBitmap?.bitmapScale).isEqualTo(1.5f)
         // 1 additional invalidation for the new full page bitmap
         assertThat(invalidationCounter).isEqualTo(18)
     }
+
+    @Test
+    fun changeViewArea_overlapWithPrevious() {
+        // 5.0 scale, viewing the lower right half of the page
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            Rect(pageSize.x / 2, pageSize.y / 2, pageSize.x, pageSize.y)
+        )
+        testDispatcher.scheduler.runCurrent()
+        val originalTileBoard = bitmapFetcher.pageContents
+        assertThat(originalTileBoard).isInstanceOf(TileBoard::class.java)
+        // This is all tiles in row > 0 && col > 0 (row 1 and col 1 are partially visible)
+        val originalVisibleIndices = setOf(5, 6, 7, 9, 10, 11, 13, 14, 15)
+        val originalBitmaps = mutableMapOf<Int, Bitmap>()
+        for (tile in (originalTileBoard as TileBoard).tiles) {
+            if (tile.index in originalVisibleIndices) {
+                assertThat(tile.bitmap).isNotNull()
+                originalBitmaps[tile.index] = requireNotNull(tile.bitmap)
+            } else {
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+        // 1 invalidation for the low-res background, 1 for each visible tile
+        val originalInvalidations = invalidationCounter
+        assertThat(originalInvalidations).isEqualTo(originalVisibleIndices.size + 1)
+
+        // 5.0 scale, viewing the middle of the page offset by 1/4 of the page's dimensions
+        bitmapFetcher.updateViewProperties(
+            5.0f,
+            Rect(pageSize.x / 4, pageSize.y / 4, pageSize.x * 3 / 4, pageSize.y * 3 / 4)
+        )
+        testDispatcher.scheduler.runCurrent()
+        val newTileBoard = bitmapFetcher.pageContents
+        // We should re-use the previous tile board
+        assertThat(newTileBoard).isEqualTo(originalTileBoard)
+        // This is all tiles in row < 3 and col < 3 (row 0 and 2, col 0 and 2 are partially visible)
+        val newVisibleIndices = setOf(0, 1, 2, 4, 5, 6, 8, 9, 10)
+        // This is all tiles that are visible in both view areas (original and new)
+        val expectedRetainedIndices = originalVisibleIndices.intersect(newVisibleIndices)
+        for (tile in (newTileBoard as TileBoard).tiles) {
+            if (tile.index in expectedRetainedIndices) {
+                // We should have re-used the previous tile Bitmap
+                assertThat(tile.bitmap).isNotNull()
+                assertThat(tile.bitmap).isEqualTo(originalBitmaps[tile.index])
+            } else if (tile.index in newVisibleIndices) {
+                // We should have fetched a new tile Bitmap
+                assertThat(tile.bitmap).isNotNull()
+            } else {
+                // We should have cleaned up the Bitmap
+                assertThat(tile.bitmap).isNull()
+            }
+        }
+
+        // Invalidations before the view area changed + 1 for each *newly* visible tile
+        assertThat(invalidationCounter)
+            .isEqualTo(
+                originalInvalidations + (newVisibleIndices.size - expectedRetainedIndices.size)
+            )
+    }
 }
diff --git a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
index f360178..ad18636 100644
--- a/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
+++ b/pdf/pdf-viewer/src/test/kotlin/androidx/pdf/view/PageTest.kt
@@ -73,7 +73,7 @@
     private fun createPage(isTouchExplorationEnabled: Boolean): Page {
         return Page(
             0,
-            pageSizePx = PAGE_SIZE,
+            pageSize = PAGE_SIZE,
             pdfDocument,
             testScope,
             MAX_BITMAP_SIZE,
@@ -97,7 +97,7 @@
     fun draw_withoutBitmap() {
         // Notably we don't call testDispatcher.scheduler.runCurrent(), so we start, but do not
         // finish, fetching a Bitmap
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         val locationInView = Rect(-60, 125, -60 + PAGE_SIZE.x, 125 + PAGE_SIZE.y)
 
         page.draw(canvasSpy, locationInView, listOf())
@@ -107,7 +107,7 @@
 
     @Test
     fun draw_withBitmap() {
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         val locationInView = Rect(50, -100, 50 + PAGE_SIZE.x, -100 + PAGE_SIZE.y)
 
@@ -127,7 +127,7 @@
 
     @Test
     fun draw_withHighlight() {
-        page.updateState(zoom = 1.5F)
+        page.setVisible(zoom = 1.5F, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         val leftEdgeInView = 650
         val topEdgeInView = -320
@@ -158,7 +158,7 @@
 
     @Test
     fun updateState_withTouchExplorationEnabled_fetchesPageText() {
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
@@ -167,7 +167,7 @@
     @Test
     fun setVisible_withTouchExplorationDisabled_doesNotFetchPageText() {
         page = createPage(isTouchExplorationEnabled = false)
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
 
         assertThat(page.pageText).isEqualTo(null)
@@ -176,20 +176,20 @@
 
     @Test
     fun updateState_doesNotFetchPageTextIfAlreadyFetched() {
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
 
-        page.updateState(zoom = 1.0f)
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isEqualTo("SampleText")
         assertThat(pageTextReadyCounter).isEqualTo(1)
     }
 
     @Test
-    fun setInvisible_cancelsPageTextFetch() {
-        page.updateState(zoom = 1.0f)
+    fun setPageInvisible_cancelsTextFetch() {
+        page.setVisible(zoom = 1.0f, FULL_PAGE_RECT)
         page.setInvisible()
         testDispatcher.scheduler.runCurrent()
         assertThat(page.pageText).isNull()
@@ -198,4 +198,5 @@
 }
 
 val PAGE_SIZE = Point(100, 150)
+val FULL_PAGE_RECT = Rect(0, 0, PAGE_SIZE.x, PAGE_SIZE.y)
 val MAX_BITMAP_SIZE = Point(500, 500)
diff --git a/performance/performance-annotation/README.md b/performance/performance-annotation/README.md
index 2ab0c3d..b37c607 100644
--- a/performance/performance-annotation/README.md
+++ b/performance/performance-annotation/README.md
@@ -1 +1 @@
-This library is a **compile-time** only dependency.
+The annotation defined in this library only affects Android.
diff --git a/performance/performance-annotation/bcv/native/current.txt b/performance/performance-annotation/bcv/native/current.txt
index 8e4fa01..f0402c6 100644
--- a/performance/performance-annotation/bcv/native/current.txt
+++ b/performance/performance-annotation/bcv/native/current.txt
@@ -6,6 +6,6 @@
 // - Show declarations: true
 
 // Library unique name: <androidx.performance:performance-annotation>
-open annotation class dalvik.annotation.optimization/NeverInline : kotlin/Annotation { // dalvik.annotation.optimization/NeverInline|null[1]
-    constructor <init>() // dalvik.annotation.optimization/NeverInline.<init>|<init>(){}[1]
+open annotation class androidx.performance.annotation/AndroidNeverInline : kotlin/Annotation { // androidx.performance.annotation/AndroidNeverInline|null[1]
+    constructor <init>() // androidx.performance.annotation/AndroidNeverInline.<init>|<init>(){}[1]
 }
diff --git a/performance/performance-annotation/shrinker-rules.pro b/performance/performance-annotation/shrinker-rules.pro
new file mode 100644
index 0000000..28c2b22
--- /dev/null
+++ b/performance/performance-annotation/shrinker-rules.pro
@@ -0,0 +1,17 @@
+# Copyright (C) 2025 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      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.
+
+-keepclassmembers class * {
+    @dalvik.annotation.optimization.NeverInline *;
+}
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java b/performance/performance-annotation/src/androidMain/kotlin/androidx/performance/annotation/AndroidNeverInline.android.kt
similarity index 73%
copy from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
copy to performance/performance-annotation/src/androidMain/kotlin/androidx/performance/annotation/AndroidNeverInline.android.kt
index f3a5276..3395134 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
+++ b/performance/performance-annotation/src/androidMain/kotlin/androidx/performance/annotation/AndroidNeverInline.android.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-package androidx.navigation.test;
+package androidx.performance.annotation
 
-public enum TestEnum {
-    VALUE_ONE, VALUE_TWO
-}
+import dalvik.annotation.optimization.NeverInline
+
+public actual typealias AndroidNeverInline = NeverInline
diff --git a/performance/performance-annotation/src/androidMain/kotlin/dalvik/annotation/optimization/NeverInline.android.kt b/performance/performance-annotation/src/androidMain/kotlin/dalvik/annotation/optimization/NeverInline.android.kt
index 50e22dc..22a6e98a 100644
--- a/performance/performance-annotation/src/androidMain/kotlin/dalvik/annotation/optimization/NeverInline.android.kt
+++ b/performance/performance-annotation/src/androidMain/kotlin/dalvik/annotation/optimization/NeverInline.android.kt
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
+@file:Suppress("RedundantVisibilityModifier")
+
 package dalvik.annotation.optimization
 
 @Retention(AnnotationRetention.BINARY)
 @Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION)
-public actual annotation class NeverInline()
+public annotation class NeverInline
diff --git a/performance/performance-annotation/src/commonMain/kotlin/androidx/performance/annotation/AndroidNeverInline.kt b/performance/performance-annotation/src/commonMain/kotlin/androidx/performance/annotation/AndroidNeverInline.kt
new file mode 100644
index 0000000..7ae676b
--- /dev/null
+++ b/performance/performance-annotation/src/commonMain/kotlin/androidx/performance/annotation/AndroidNeverInline.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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:OptIn(ExperimentalMultiplatform::class)
+
+package androidx.performance.annotation
+
+/**
+ * Indicates that an API should never be inlined by ART on Android.
+ *
+ * [AndroidNeverInline] can be used to annotate methods that should not be inlined into other
+ * methods. Methods that are not called frequently, are never speed-critical, or are only used for
+ * debugging do not necessarily need to run quickly. Applying this annotation to prevent these
+ * methods from being inlined will return some size improvements in .odex files.
+ */
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION)
+@OptionalExpectation
+public expect annotation class AndroidNeverInline()
diff --git a/performance/performance-annotation/src/commonMain/kotlin/dalvik/annotation/optimization/NeverInline.kt b/performance/performance-annotation/src/commonMain/kotlin/dalvik/annotation/optimization/NeverInline.kt
deleted file mode 100644
index 89cbfe3..0000000
--- a/performance/performance-annotation/src/commonMain/kotlin/dalvik/annotation/optimization/NeverInline.kt
+++ /dev/null
@@ -1,35 +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.
- */
-
-@file:OptIn(ExperimentalMultiplatform::class)
-
-package dalvik.annotation.optimization
-
-/**
- * Indicates that an API should never be inlined by ART on Android.
- *
- * [NeverInline] can be used to annotate methods that should not be inlined into other methods.
- * Methods that are not called frequently, are never speed-critical, or are only used for debugging
- * do not necessarily need to run quickly. Applying this annotation to prevent these methods from
- * being inlined will return some size improvements in .odex files.
- *
- * Prefer using the `AndroidNeverInline` typealias instead of this annotation directly to emphasize
- * it only affects Android targets.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION)
-@OptionalExpectation
-public expect annotation class NeverInline()
diff --git a/privacysandbox/tools/integration-tests/testsdk/src/main/java/androidx/privacysandbox/tools/integration/testsdk/MySdk.kt b/privacysandbox/tools/integration-tests/testsdk/src/main/java/androidx/privacysandbox/tools/integration/testsdk/MySdk.kt
index 454727b..b22e333 100644
--- a/privacysandbox/tools/integration-tests/testsdk/src/main/java/androidx/privacysandbox/tools/integration/testsdk/MySdk.kt
+++ b/privacysandbox/tools/integration-tests/testsdk/src/main/java/androidx/privacysandbox/tools/integration/testsdk/MySdk.kt
@@ -19,12 +19,12 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.os.Bundle
-import android.os.IBinder
 import android.view.View
 import android.widget.TextView
 import androidx.privacysandbox.tools.PrivacySandboxInterface
 import androidx.privacysandbox.tools.PrivacySandboxService
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.util.concurrent.Executor
 
 @PrivacySandboxService
@@ -49,7 +49,7 @@
 class TextViewAdImpl : TextViewAd {
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/callbacks/output/com/sdkwithcallbacks/MyUiInterfaceClientProxy.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/callbacks/output/com/sdkwithcallbacks/MyUiInterfaceClientProxy.kt
index 4d8eeb9..32d10ad 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/callbacks/output/com/sdkwithcallbacks/MyUiInterfaceClientProxy.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/callbacks/output/com/sdkwithcallbacks/MyUiInterfaceClientProxy.kt
@@ -2,10 +2,10 @@
 
 import android.content.Context
 import android.os.Bundle
-import android.os.IBinder
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.util.concurrent.Executor
 
 public class MyUiInterfaceClientProxy(
@@ -21,14 +21,14 @@
 
     public override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
         clientExecutor: Executor,
         client: SandboxedUiAdapter.SessionClient,
     ) {
-        sandboxedUiAdapter.openSession(context, windowInputToken, initialWidth, initialHeight,
+        sandboxedUiAdapter.openSession(context, sessionConstants, initialWidth, initialHeight,
                 isZOrderOnTop, clientExecutor, client)
     }
 }
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
index d7f90e3..8583243 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
@@ -2,10 +2,10 @@
 
 import android.content.Context
 import android.os.Bundle
-import android.os.IBinder
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.util.concurrent.Executor
 
 public class MySecondInterfaceClientProxy(
@@ -21,14 +21,14 @@
 
     public override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
         clientExecutor: Executor,
         client: SandboxedUiAdapter.SessionClient,
     ) {
-        sandboxedUiAdapter.openSession(context, windowInputToken, initialWidth, initialHeight,
+        sandboxedUiAdapter.openSession(context, sessionConstants, initialWidth, initialHeight,
                 isZOrderOnTop, clientExecutor, client)
     }
 }
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/MyUiInterfaceClientProxy.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/MyUiInterfaceClientProxy.kt
index 86709a8..7bb8599 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/MyUiInterfaceClientProxy.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/MyUiInterfaceClientProxy.kt
@@ -2,10 +2,10 @@
 
 import android.content.Context
 import android.os.Bundle
-import android.os.IBinder
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.util.concurrent.Executor
 
 public class MyUiInterfaceClientProxy(
@@ -21,14 +21,14 @@
 
     public override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
         clientExecutor: Executor,
         client: SandboxedUiAdapter.SessionClient,
     ) {
-        sandboxedUiAdapter.openSession(context, windowInputToken, initialWidth, initialHeight,
+        sandboxedUiAdapter.openSession(context, sessionConstants, initialWidth, initialHeight,
                 isZOrderOnTop, clientExecutor, client)
     }
 }
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
index 54d5210..a8f1ee1 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
@@ -150,7 +150,10 @@
             addParameters(
                 listOf(
                     ParameterSpec(contextPropertyName, contextClass),
-                    ParameterSpec("windowInputToken", ClassName("android.os", "IBinder")),
+                    ParameterSpec(
+                        "sessionConstants",
+                        ClassName("androidx.privacysandbox.ui.core", "SessionConstants")
+                    ),
                     ParameterSpec("initialWidth", Types.int.poetClassName()),
                     ParameterSpec("initialHeight", Types.int.poetClassName()),
                     ParameterSpec("isZOrderOnTop", Types.boolean.poetClassName()),
@@ -165,7 +168,7 @@
                 )
             )
             addStatement(
-                "$sandboxedUiAdapterPropertyName.openSession(%N, windowInputToken, initialWidth, " +
+                "$sandboxedUiAdapterPropertyName.openSession(%N, sessionConstants, initialWidth, " +
                     "initialHeight, isZOrderOnTop, clientExecutor, client)",
                 contextPropertyName,
             )
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
index bf67e4d..ca604a5 100644
--- a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
@@ -26,7 +26,6 @@
 import android.net.Uri
 import android.os.Bundle
 import android.os.Handler
-import android.os.IBinder
 import android.os.Looper
 import android.provider.Settings
 import android.util.Log
@@ -41,6 +40,7 @@
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
 import androidx.privacysandbox.ui.client.view.SandboxedSdkView
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.provider.AbstractSandboxedUiAdapter
 import androidx.webkit.WebViewAssetLoader
 import androidx.webkit.WebViewClientCompat
@@ -62,7 +62,7 @@
 
         override fun openSession(
             context: Context,
-            windowInputToken: IBinder,
+            sessionConstants: SessionConstants,
             initialWidth: Int,
             initialHeight: Int,
             isZOrderOnTop: Boolean,
diff --git a/privacysandbox/ui/integration-tests/testapp/build.gradle b/privacysandbox/ui/integration-tests/testapp/build.gradle
index a9a297b..e88938e 100644
--- a/privacysandbox/ui/integration-tests/testapp/build.gradle
+++ b/privacysandbox/ui/integration-tests/testapp/build.gradle
@@ -37,6 +37,16 @@
         }
     }
 
+    experimentalProperties["android.privacySandboxSdk.apiGenerator"] =
+            project.dependencies.create(project(":privacysandbox:tools:tools-apigenerator"))
+    experimentalProperties["android.privacySandboxSdk.apiGenerator.generatedRuntimeDependencies"] =
+            [libs.kotlinStdlib.get(),
+             libs.kotlinCoroutinesAndroid.get(),
+             libs.kotlinCoroutinesCore.get(),
+             project.dependencies.create(project(":privacysandbox:ui:ui-core")),
+             project.dependencies.create(project(":privacysandbox:ui:ui-client"))
+            ]
+
     privacySandbox {
         enable = true
     }
diff --git a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/LazyListFragment.kt b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/LazyListFragment.kt
new file mode 100644
index 0000000..d220ae7
--- /dev/null
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/LazyListFragment.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.privacysandbox.ui.integration.testapp
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.compose.ui.unit.dp
+import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
+import androidx.privacysandbox.ui.client.view.SandboxedSdkUi
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.launch
+
+class LazyListFragment : BaseFragment() {
+
+    private var adapters by mutableStateOf(listOf<AdAdapterItem>())
+
+    override fun handleLoadAdFromDrawer(
+        adType: Int,
+        mediationOption: Int,
+        drawViewabilityLayer: Boolean
+    ) {
+        currentAdType = adType
+        currentMediationOption = mediationOption
+        shouldDrawViewabilityLayer = drawViewabilityLayer
+        updateBannerAdAdapter()
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        initializeBannerAdAdapter(count = 10)
+        return ComposeView(requireContext()).apply {
+            // Dispose of the Composition when the view's LifecycleOwner is destroyed
+            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+            setContent { AdsList(adapters) }
+        }
+    }
+
+    @Composable
+    private fun AdsList(adAdapters: List<AdAdapterItem>) {
+        LazyColumn(
+            modifier = Modifier.fillMaxSize().padding(16.dp),
+            verticalArrangement = Arrangement.spacedBy(16.dp),
+        ) {
+            items(
+                items = adAdapters,
+                key = { adapterWithId -> adapterWithId.id },
+                contentType = { adapterItem -> adapterItem.contentType }
+            ) { adapterWithId ->
+                SandboxedSdkUi(
+                    adapterWithId.adapter,
+                    Modifier.fillParentMaxSize(),
+                    providerUiOnTop = providerUiOnTop
+                )
+            }
+        }
+    }
+
+    private fun initializeBannerAdAdapter(count: Int) {
+        val coroutineScope = MainScope()
+        coroutineScope.launch {
+            val mutableAdapterList = mutableListOf<AdAdapterItem>()
+            for (i in 1..count) {
+                mutableAdapterList.add(
+                    AdAdapterItem(
+                        id = i,
+                        adapter =
+                            SandboxedUiAdapterFactory.createFromCoreLibInfo(
+                                getSdkApi()
+                                    .loadBannerAd(
+                                        currentAdType,
+                                        currentMediationOption,
+                                        false,
+                                        shouldDrawViewabilityLayer,
+                                    )
+                            )
+                    )
+                )
+            }
+            adapters = mutableAdapterList
+        }
+    }
+
+    private fun updateBannerAdAdapter() {
+        val coroutineScope = MainScope()
+        coroutineScope.launch {
+            val updatedAdapterList = mutableListOf<AdAdapterItem>()
+            adapters.forEach { adapterWithId ->
+                updatedAdapterList.add(
+                    AdAdapterItem(
+                        id = adapterWithId.id,
+                        adapter =
+                            SandboxedUiAdapterFactory.createFromCoreLibInfo(
+                                getSdkApi()
+                                    .loadBannerAd(
+                                        currentAdType,
+                                        currentMediationOption,
+                                        false,
+                                        shouldDrawViewabilityLayer,
+                                    )
+                            )
+                    )
+                )
+            }
+            adapters = updatedAdapterList
+        }
+    }
+
+    private data class AdAdapterItem(
+        val id: Int,
+        // TODO(b/391558988): Specify content type for PoolingContainer CUJ
+        // in View world for consistency
+        val contentType: String = "BannerAd_$id",
+        val adapter: SandboxedUiAdapter
+    )
+}
diff --git a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
index 8467ece..ae42f769 100644
--- a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
@@ -309,7 +309,14 @@
                     switchContentFragment(ScrollFragment(), menuItem.title)
                 }
             R.id.item_pooling_container ->
-                switchContentFragment(PoolingContainerFragment(), menuItem.title)
+                if (useCompose) {
+                    switchContentFragment(
+                        LazyListFragment(),
+                        "${menuItem.title} ${getString(R.string.compose)}"
+                    )
+                } else {
+                    switchContentFragment(PoolingContainerFragment(), menuItem.title)
+                }
             R.id.item_fullscreen ->
                 if (useCompose) {
                     switchContentFragment(
diff --git a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/ResizeComposeFragment.kt b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/ResizeComposeFragment.kt
index c537976..9d726f2 100644
--- a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/ResizeComposeFragment.kt
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/ResizeComposeFragment.kt
@@ -22,6 +22,7 @@
 import android.view.ViewGroup
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
@@ -31,10 +32,13 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.ViewCompositionStrategy
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -60,6 +64,14 @@
         val newHeight = newSize(currentDimension.height.value.toInt(), maxSizePixels).dp
         bannerDimension = BannerDimension(newWidth, newHeight)
     }
+    private var bannerPadding by mutableStateOf(BannerPadding())
+    private val onChangePaddingClicked: (BannerDimension) -> Unit = { currentDimension ->
+        val maxHorizontalPadding = (currentDimension.width.value.toInt() / 2) - 10
+        val maxVerticalPadding = (currentDimension.height.value.toInt() / 2) - 10
+        val horizontalPadding = (10..maxHorizontalPadding).random().dp
+        val verticalPadding = (10..maxVerticalPadding).random().dp
+        bannerPadding = BannerPadding(horizontalPadding, verticalPadding)
+    }
 
     override fun handleLoadAdFromDrawer(
         adType: Int,
@@ -81,7 +93,15 @@
         return ComposeView(requireContext()).apply {
             // Dispose of the Composition when the view's LifecycleOwner is destroyed
             setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
-            setContent { ResizeableBannerAd(adapter, bannerDimension, onBannerDimensionChanged) }
+            setContent {
+                ResizeableBannerAd(
+                    adapter,
+                    bannerDimension,
+                    onBannerDimensionChanged,
+                    bannerPadding,
+                    onChangePaddingClicked
+                )
+            }
         }
     }
 
@@ -89,21 +109,40 @@
     fun ResizeableBannerAd(
         adapter: SandboxedUiAdapter?,
         bannerDimension: BannerDimension,
-        onResizeClicked: (BannerDimension) -> Unit
+        onResizeClicked: (BannerDimension) -> Unit,
+        bannerPadding: BannerPadding,
+        onChangePaddingClicked: (BannerDimension) -> Unit,
     ) {
         Column(
             modifier = Modifier.fillMaxSize().padding(16.dp),
             verticalArrangement = Arrangement.Top,
             horizontalAlignment = Alignment.Start
         ) {
-            val sandboxedSdkUiModifier =
+            val localDensity = LocalDensity.current
+            var ssvHeight by remember { mutableStateOf(0.dp) }
+            var ssvWidth by remember { mutableStateOf(0.dp) }
+
+            var sandboxedSdkUiModifier =
+                Modifier.onGloballyPositioned { coordinates ->
+                        with(localDensity) {
+                            ssvWidth = coordinates.size.width.toDp()
+                            ssvHeight = coordinates.size.height.toDp()
+                        }
+                    }
+                    .padding(
+                        horizontal = bannerPadding.horizontalPadding,
+                        vertical = bannerPadding.verticalPadding
+                    )
+
+            sandboxedSdkUiModifier =
                 if (bannerDimension.height != 0.dp && bannerDimension.width != 0.dp) {
-                    Modifier.width(bannerDimension.width)
+                    sandboxedSdkUiModifier
+                        .width(bannerDimension.width)
                         .weight(
                             1f,
                         )
                 } else {
-                    Modifier.fillMaxWidth().weight(1f)
+                    sandboxedSdkUiModifier.fillMaxWidth().weight(1f)
                 }
 
             Text("Ad state: $adEventText")
@@ -128,7 +167,12 @@
                         },
                 )
             }
-            Button(onClick = { onResizeClicked(bannerDimension) }) { Text("Resize") }
+            Row {
+                Button(onClick = { onResizeClicked(bannerDimension) }) { Text("Resize") }
+                Button(onClick = { onChangePaddingClicked(BannerDimension(ssvWidth, ssvHeight)) }) {
+                    Text("Change padding")
+                }
+            }
         }
     }
 
@@ -149,4 +193,6 @@
     }
 
     data class BannerDimension(val width: Dp = 0.dp, val height: Dp = 0.dp)
+
+    data class BannerPadding(val horizontalPadding: Dp = 0.dp, val verticalPadding: Dp = 0.dp)
 }
diff --git a/privacysandbox/ui/integration-tests/testsdkprovider/build.gradle b/privacysandbox/ui/integration-tests/testsdkprovider/build.gradle
index 767199b..a4e036b0 100644
--- a/privacysandbox/ui/integration-tests/testsdkprovider/build.gradle
+++ b/privacysandbox/ui/integration-tests/testsdkprovider/build.gradle
@@ -34,6 +34,16 @@
     privacySandbox {
         enable = true
     }
+
+    experimentalProperties["android.privacySandboxSdk.apiGenerator"] =
+            project.dependencies.create(project(":privacysandbox:tools:tools-apigenerator"))
+    experimentalProperties["android.privacySandboxSdk.apiGenerator.generatedRuntimeDependencies"] =
+            [libs.kotlinStdlib.get(),
+             libs.kotlinCoroutinesAndroid.get(),
+             libs.kotlinCoroutinesCore.get(),
+             project.dependencies.create(project(":privacysandbox:ui:ui-core")),
+             project.dependencies.create(project(":privacysandbox:ui:ui-client"))
+            ]
 }
 
 dependencies {
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/FailingTestSandboxedUiAdapter.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/FailingTestSandboxedUiAdapter.kt
index 79dd0c8..0582407 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/FailingTestSandboxedUiAdapter.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/FailingTestSandboxedUiAdapter.kt
@@ -17,15 +17,15 @@
 package androidx.privacysandbox.ui.client.test
 
 import android.content.Context
-import android.os.IBinder
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.provider.AbstractSandboxedUiAdapter
 import java.util.concurrent.Executor
 
 class FailingTestSandboxedUiAdapter : AbstractSandboxedUiAdapter() {
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkUiTest.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkUiTest.kt
index e057517..30a4067 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkUiTest.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkUiTest.kt
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.ReusableContentHost
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
@@ -542,6 +543,117 @@
         assertThat(sandboxedSdkViewUiInfo?.onScreenGeometry?.isEmpty).isFalse()
     }
 
+    @Test
+    fun sessionRemainsOpenWhenSandboxedSdkUiIsDetachedAndNotReleased() {
+        var attached by mutableStateOf(true)
+
+        composeTestRule.setContent {
+            ReusableContentHost(attached) {
+                SandboxedSdkUi(
+                    sandboxedUiAdapter = testSandboxedUiAdapter,
+                    modifier = Modifier.requiredSize(size),
+                    providerUiOnTop = providerUiOnTop,
+                    sandboxedSdkViewEventListener = eventListener
+                )
+            }
+        }
+
+        testSandboxedUiAdapter.assertSessionOpened()
+
+        attached = false
+        testSandboxedUiAdapter.assertSessionNotClosed()
+
+        attached = true
+        testSandboxedUiAdapter.assertSessionNotClosed()
+    }
+
+    @Test
+    fun sessionClosesWhenSandboxedSdkUiIsRemovedFromComposition() {
+        var showContent by mutableStateOf(true)
+
+        composeTestRule.setContent {
+            if (showContent) {
+                SandboxedSdkUi(
+                    sandboxedUiAdapter = testSandboxedUiAdapter,
+                    modifier = Modifier.requiredSize(size),
+                    providerUiOnTop = providerUiOnTop,
+                    sandboxedSdkViewEventListener = eventListener
+                )
+            }
+        }
+
+        testSandboxedUiAdapter.assertSessionOpened()
+
+        showContent = false
+        composeTestRule.waitForIdle()
+
+        testSandboxedUiAdapter.assertSessionClosed()
+    }
+
+    @Test
+    fun reAddEventListenerWhenSandboxedSdkUiIsReAttachedInLazyList() {
+        var attached by mutableStateOf(true)
+
+        composeTestRule.setContent {
+            ReusableContentHost(attached) {
+                SandboxedSdkUi(
+                    sandboxedUiAdapter = testSandboxedUiAdapter,
+                    modifier = Modifier.requiredSize(size),
+                    providerUiOnTop = providerUiOnTop,
+                    sandboxedSdkViewEventListener = eventListener
+                )
+            }
+        }
+
+        // When session is open, the events are received
+        assertThat(eventListener.uiDisplayedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+
+        attached = false
+        composeTestRule.waitForIdle()
+
+        attached = true
+        composeTestRule.waitForIdle()
+
+        // When SandboxedSdkUi is re-attached event listener is added back
+        assertThat(eventListener.uiDisplayedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+    }
+
+    @Test
+    fun onUiClosedWhenSandboxedSdkUiIsRemovedFromComposition() {
+        var showContent by mutableStateOf(true)
+        var attached by mutableStateOf(true)
+
+        composeTestRule.setContent {
+            if (showContent) {
+                ReusableContentHost(attached) {
+                    SandboxedSdkUi(
+                        sandboxedUiAdapter = testSandboxedUiAdapter,
+                        modifier = Modifier.requiredSize(size),
+                        providerUiOnTop = providerUiOnTop,
+                        sandboxedSdkViewEventListener = eventListener
+                    )
+                }
+            }
+        }
+
+        // verify onUiDisplayed() is called
+        assertThat(eventListener.uiDisplayedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+
+        // detach SandboxedSdkUi from composition hierarchy of ReusableContentHost
+        attached = false
+        composeTestRule.waitForIdle()
+
+        // verify onUiClosed() is not called
+        assertThat(eventListener.sessionClosedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isFalse()
+
+        // remove SandboxedSdkUi from composition hierarchy
+        showContent = false
+        composeTestRule.waitForIdle()
+
+        // verify onUiClosed() is called
+        assertThat(eventListener.sessionClosedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+    }
+
     private fun addNodeToLayout() {
         composeTestRule.setContent {
             SandboxedSdkUi(
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
index 9002a19..a9300b4 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.ActivityInfo
+import android.os.Build
 import android.os.IBinder
 import android.view.SurfaceView
 import android.view.View
@@ -27,10 +28,12 @@
 import android.view.ViewTreeObserver
 import android.widget.LinearLayout
 import android.widget.TextView
+import androidx.annotation.RequiresApi
 import androidx.lifecycle.Lifecycle
 import androidx.privacysandbox.ui.client.view.SandboxedSdkView
 import androidx.privacysandbox.ui.core.BackwardCompatUtil
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.integration.testingutils.TestEventListener
 import androidx.privacysandbox.ui.provider.AbstractSandboxedUiAdapter
 import androidx.test.ext.junit.rules.ActivityScenarioRule
@@ -270,7 +273,7 @@
         class CustomUiAdapter : AbstractSandboxedUiAdapter() {
             override fun openSession(
                 context: Context,
-                windowInputToken: IBinder,
+                sessionConstants: SessionConstants,
                 initialWidth: Int,
                 initialHeight: Int,
                 isZOrderOnTop: Boolean,
@@ -307,7 +310,7 @@
         class CustomUiAdapter : AbstractSandboxedUiAdapter() {
             override fun openSession(
                 context: Context,
-                windowInputToken: IBinder,
+                sessionConstants: SessionConstants,
                 initialWidth: Int,
                 initialHeight: Int,
                 isZOrderOnTop: Boolean,
@@ -441,8 +444,10 @@
      */
     @SuppressLint("NewApi") // Test runs on U+ devices
     @Test
-    fun inputTokenIsCorrect() {
-        // Input token is only needed when provider can be located on a separate process.
+    fun windowInputTokenIsCorrect() {
+        // Input token is only needed when provider can be located on a separate process. It is
+        // also only needed on U devices, on V+ we will use InputTransferToken
+        assumeTrue(Build.VERSION.SDK_INT == Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
         assumeTrue(BackwardCompatUtil.canProviderBeRemote())
         lateinit var layout: LinearLayout
         val surfaceView = SurfaceView(context)
@@ -471,7 +476,19 @@
         // Verify that the UI adapter receives the same host token object when opening a session.
         addViewToLayout()
         testSandboxedUiAdapter.assertSessionOpened()
-        assertThat(testSandboxedUiAdapter.inputToken).isEqualTo(token)
+        assertThat(testSandboxedUiAdapter.sessionConstants?.windowInputToken).isEqualTo(token)
+    }
+
+    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    @Test
+    fun inputTransferTokenIsCorrect() {
+        // InputTransferToken is only sent on V+
+        assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+        addViewToLayoutAndWaitToBeActive()
+        val inputTransferToken = view.rootSurfaceControl?.inputTransferToken
+        assertThat(testSandboxedUiAdapter.sessionConstants?.inputTransferToken).isNotNull()
+        assertThat(testSandboxedUiAdapter.sessionConstants?.inputTransferToken)
+            .isEqualTo(inputTransferToken)
     }
 
     @Ignore("b/307829956")
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/TestSandboxedUiAdapter.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/TestSandboxedUiAdapter.kt
index f9ebe61..1eff37a 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/TestSandboxedUiAdapter.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/TestSandboxedUiAdapter.kt
@@ -18,11 +18,11 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.os.Bundle
-import android.os.IBinder
 import android.os.SystemClock
 import android.view.View
 import androidx.privacysandbox.ui.core.SandboxedSdkViewUiInfo
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.provider.AbstractSandboxedUiAdapter
 import com.google.common.truth.Truth
 import java.util.concurrent.CountDownLatch
@@ -35,7 +35,8 @@
     var internalClient: SandboxedUiAdapter.SessionClient? = null
     var testSession: TestSession? = null
     var isZOrderOnTop = true
-    var inputToken: IBinder? = null
+    var sessionConstants: SessionConstants? = null
+
     // When set to true, the onSessionOpened callback will only be invoked when specified
     // by the test. This is to test race conditions when the session is being loaded.
     var delayOpenSessionCallback = false
@@ -46,7 +47,7 @@
 
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
@@ -61,7 +62,7 @@
             }
             isSessionOpened = true
             this.isZOrderOnTop = isZOrderOnTop
-            this.inputToken = windowInputToken
+            this.sessionConstants = sessionConstants
             openSessionLatch.countDown()
         }
     }
@@ -102,6 +103,13 @@
             .isFalse()
     }
 
+    internal fun assertSessionClosed() {
+        Truth.assertThat(
+                sessionClosedLatch.await(SandboxedSdkViewTest.TIMEOUT, TimeUnit.MILLISECONDS)
+            )
+            .isTrue()
+    }
+
     inner class TestSession(context: Context, override val signalOptions: Set<String>) :
         SandboxedUiAdapter.Session {
         var zOrderChangedLatch: CountDownLatch = CountDownLatch(1)
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/ClientDelegatingAdapter.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/ClientDelegatingAdapter.kt
index 404139d..7eee3a9 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/ClientDelegatingAdapter.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/ClientDelegatingAdapter.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.os.Bundle
-import android.os.IBinder
 import androidx.annotation.GuardedBy
 import androidx.core.util.Consumer
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory.createFromCoreLibInfo
@@ -29,6 +28,7 @@
 import androidx.privacysandbox.ui.core.ISessionRefreshCallback
 import androidx.privacysandbox.ui.core.RemoteCallManager.tryToCallRemoteObject
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.util.concurrent.Executor
 import kotlin.coroutines.resume
 import kotlinx.coroutines.*
@@ -143,7 +143,7 @@
      */
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
@@ -153,7 +153,7 @@
         val delegateUsed: SandboxedUiAdapter = synchronized(lock) { latestDelegate }
         delegateUsed.openSession(
             context,
-            windowInputToken,
+            sessionConstants,
             initialWidth,
             initialHeight,
             isZOrderOnTop,
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt
index e80268a..2339430 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt
@@ -22,7 +22,6 @@
 import android.hardware.display.DisplayManager
 import android.os.Build
 import android.os.Bundle
-import android.os.IBinder
 import android.util.Log
 import android.view.Display
 import android.view.SurfaceControlViewHost
@@ -39,6 +38,7 @@
 import androidx.privacysandbox.ui.core.RemoteCallManager.closeRemoteSession
 import androidx.privacysandbox.ui.core.RemoteCallManager.tryToCallRemoteObject
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import java.lang.reflect.InvocationHandler
 import java.lang.reflect.Method
 import java.lang.reflect.Proxy
@@ -113,6 +113,16 @@
                 uiProviderBinder.javaClass.classLoader
             )
 
+        private val targetSessionConstantsClass =
+            Class.forName(
+                SessionConstants::class.java.name,
+                /* initialize = */ false,
+                uiProviderBinder.javaClass.classLoader
+            )
+
+        private val targetSessionConstantsCompanionObject =
+            targetSessionConstantsClass.getDeclaredField("Companion").get(null)
+
         // The adapterInterface provided must have a openSession method on its class.
         // Since the object itself has been instantiated on a different classloader, we
         // need reflection to get hold of it.
@@ -125,7 +135,7 @@
                 .getMethod(
                     "openSession",
                     Context::class.java,
-                    IBinder::class.java,
+                    targetSessionConstantsClass,
                     Int::class.java,
                     Int::class.java,
                     Boolean::class.java,
@@ -133,9 +143,15 @@
                     targetSessionClientClass
                 )
 
+        private val fromBundleMethod: Method =
+            targetSessionConstantsCompanionObject.javaClass.getMethod(
+                "fromBundle",
+                Bundle::class.java
+            )
+
         override fun openSession(
             context: Context,
-            windowInputToken: IBinder,
+            sessionConstants: SessionConstants,
             initialWidth: Int,
             initialHeight: Int,
             isZOrderOnTop: Boolean,
@@ -154,7 +170,10 @@
                 openSessionMethod.invoke(
                     uiProviderBinder,
                     context,
-                    windowInputToken,
+                    fromBundleMethod.invoke(
+                        targetSessionConstantsCompanionObject,
+                        SessionConstants.toBundle(sessionConstants)
+                    ),
                     initialWidth,
                     initialHeight,
                     isZOrderOnTop,
@@ -270,7 +289,7 @@
 
         override fun openSession(
             context: Context,
-            windowInputToken: IBinder,
+            sessionConstants: SessionConstants,
             initialWidth: Int,
             initialHeight: Int,
             isZOrderOnTop: Boolean,
@@ -283,7 +302,7 @@
 
             tryToCallRemoteObject(adapterInterface) {
                 this.openRemoteSession(
-                    windowInputToken,
+                    SessionConstants.toBundle(sessionConstants),
                     displayId,
                     initialWidth,
                     initialHeight,
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkUi.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkUi.kt
index 29f873a..1a1b137 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkUi.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkUi.kt
@@ -17,8 +17,6 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.viewinterop.AndroidView
@@ -41,33 +39,17 @@
     providerUiOnTop: Boolean = true,
     sandboxedSdkViewEventListener: SandboxedSdkViewEventListener? = null
 ) {
-    val delegatedListener =
-        remember {
-                object : SandboxedSdkViewEventListener {
-                    var delegate by mutableStateOf(sandboxedSdkViewEventListener)
-
-                    override fun onUiDisplayed() {
-                        delegate?.onUiDisplayed()
-                    }
-
-                    override fun onUiError(error: Throwable) {
-                        delegate?.onUiError(error)
-                    }
-
-                    override fun onUiClosed() {
-                        delegate?.onUiClosed()
-                    }
-                }
-            }
-            .apply { delegate = sandboxedSdkViewEventListener }
     AndroidView(
         modifier = modifier,
-        factory = { context ->
-            SandboxedSdkView(context).apply { setEventListener(delegatedListener) }
-        },
+        factory = { context -> SandboxedSdkView(context).apply { isInComposeNode = true } },
         update = { view ->
-            view.setAdapter(sandboxedUiAdapter)
-            view.orderProviderUiAboveClientUi(providerUiOnTop)
-        }
+            view.apply {
+                setEventListener(sandboxedSdkViewEventListener)
+                setAdapter(sandboxedUiAdapter)
+                orderProviderUiAboveClientUi(providerUiOnTop)
+            }
+        },
+        onReset = { view -> view.setEventListener(null) },
+        onRelease = { view -> view.closeClient() }
     )
 }
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
index 01e3212..a4f35ac 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
@@ -18,9 +18,7 @@
 
 import android.content.Context
 import android.content.res.Configuration
-import android.os.Binder
 import android.os.Build
-import android.os.IBinder
 import android.util.AttributeSet
 import android.view.SurfaceView
 import android.view.View
@@ -35,6 +33,7 @@
 import androidx.customview.poolingcontainer.removePoolingContainerListener
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient
+import androidx.privacysandbox.ui.core.SessionConstants
 import kotlin.math.min
 
 /** A listener for events relating to the SandboxedSdkView UI presentation. */
@@ -81,14 +80,15 @@
     private var requestedWidth = -1
     private var requestedHeight = -1
     private var isTransitionGroupSet = false
-    private var windowInputToken: IBinder? = null
     private var previousChildWidth = -1
     private var previousChildHeight = -1
+    private var sessionConstants: SessionConstants? = null
     private var viewContainingPoolingContainerListener: View? = null
     private var poolingContainerListener = PoolingContainerListener {}
     private var eventListener: SandboxedSdkViewEventListener? = null
     private val frameCommitCallback = Runnable { eventListener?.onUiDisplayed() }
     internal var signalMeasurer: SandboxedSdkViewSignalMeasurer? = null
+    internal var isInComposeNode = false
 
     /**
      * Sets an event listener to the [SandboxedSdkView] and starts reporting the new events. To
@@ -136,7 +136,7 @@
         val adapter = adapter
         if (
             adapter != null &&
-                windowInputToken != null &&
+                sessionConstants != null &&
                 width > 0 &&
                 height > 0 &&
                 windowVisibility == View.VISIBLE
@@ -145,7 +145,7 @@
                 client = Client(this)
                 adapter.openSession(
                     context,
-                    windowInputToken!!,
+                    sessionConstants!!,
                     width,
                     height,
                     isZOrderOnTop,
@@ -157,7 +157,7 @@
                 this.refreshCallback = callback
                 adapter.openSession(
                     context,
-                    windowInputToken!!,
+                    sessionConstants!!,
                     width,
                     height,
                     isZOrderOnTop,
@@ -307,10 +307,10 @@
         signalMeasurer?.maybeSendSignals()
     }
 
-    private fun closeClient() {
+    internal fun closeClient() {
         client?.close()
         client = null
-        windowInputToken = null
+        sessionConstants = null
     }
 
     private fun attachPoolingContainerListener() {
@@ -345,16 +345,16 @@
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
         addCallbacksOnWindowAttachment()
-        if (client == null || viewContainingPoolingContainerListener == null) {
-            if (this.isWithinPoolingContainer) {
-                attachPoolingContainerListener()
-            }
+        if (viewContainingPoolingContainerListener == null && this.isWithinPoolingContainer) {
+            attachPoolingContainerListener()
+        }
+        if (client == null) {
             CompatImpl.deriveInputTokenAndOpenSession(context, this)
         }
     }
 
     override fun onDetachedFromWindow() {
-        if (!this.isWithinPoolingContainer) {
+        if (!this.isInComposeNode && !this.isWithinPoolingContainer) {
             closeClient()
         }
         removeCallbacksOnWindowDetachment()
@@ -534,13 +534,12 @@
     private object CompatImpl {
 
         fun deriveInputTokenAndOpenSession(context: Context, sandboxedSdkView: SandboxedSdkView) {
-            // TODO(b/284147223): Remove this logic in V+
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+                Api35PlusImpl.setInputTransferTokenAndOpenSession(sandboxedSdkView)
+            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
                 Api34PlusImpl.attachTemporarySurfaceViewAndOpenSession(context, sandboxedSdkView)
             } else {
-                // the openSession signature requires a non-null input token, so the session
-                // will not be opened until this is set
-                sandboxedSdkView.windowInputToken = Binder()
+                sandboxedSdkView.sessionConstants = SessionConstants()
                 sandboxedSdkView.checkClientOpenSession()
             }
         }
@@ -559,6 +558,19 @@
             }
         }
 
+        @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+        private object Api35PlusImpl {
+            @JvmStatic
+            fun setInputTransferTokenAndOpenSession(sandboxedSdkView: SandboxedSdkView) {
+                sandboxedSdkView.sessionConstants =
+                    SessionConstants(
+                        windowInputToken = null,
+                        inputTransferToken = sandboxedSdkView.rootSurfaceControl?.inputTransferToken
+                    )
+                sandboxedSdkView.checkClientOpenSession()
+            }
+        }
+
         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
         private object Api34PlusImpl {
 
@@ -573,7 +585,13 @@
                         override fun onViewAttachedToWindow(view: View) {
                             view.removeOnAttachStateChangeListener(this)
                             @Suppress("DEPRECATION")
-                            sandboxedSdkView.windowInputToken = surfaceView.hostToken
+                            surfaceView.hostToken?.let {
+                                sandboxedSdkView.sessionConstants =
+                                    SessionConstants(
+                                        windowInputToken = it,
+                                        inputTransferToken = null
+                                    )
+                            }
                             sandboxedSdkView.removeTemporarySurfaceView(surfaceView)
                             sandboxedSdkView.checkClientOpenSession()
                         }
diff --git a/privacysandbox/ui/ui-core/api/current.txt b/privacysandbox/ui/ui-core/api/current.txt
index 313129f..8a52b96 100644
--- a/privacysandbox/ui/ui-core/api/current.txt
+++ b/privacysandbox/ui/ui-core/api/current.txt
@@ -5,7 +5,7 @@
     ctor public DelegatingSandboxedUiAdapter(android.os.Bundle delegate);
     method public void addDelegateChangeListener(androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter.DelegateChangeListener listener);
     method public android.os.Bundle getDelegate();
-    method public void openSession(android.content.Context context, android.os.IBinder windowInputToken, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+    method public void openSession(android.content.Context context, androidx.privacysandbox.ui.core.SessionConstants sessionConstants, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
     method public void removeDelegateChangeListener(androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter.DelegateChangeListener listener);
     method public suspend Object? updateDelegate(android.os.Bundle delegate, kotlin.coroutines.Continuation<? super kotlin.Unit>);
   }
@@ -41,7 +41,7 @@
   }
 
   public interface SandboxedUiAdapter {
-    method public void openSession(android.content.Context context, android.os.IBinder windowInputToken, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+    method public void openSession(android.content.Context context, androidx.privacysandbox.ui.core.SessionConstants sessionConstants, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
   }
 
   public static interface SandboxedUiAdapter.Session extends java.lang.AutoCloseable {
@@ -70,6 +70,17 @@
     field public static final int apiVersion = 1; // 0x1
   }
 
+  public final class SessionConstants {
+    method public android.window.InputTransferToken? getInputTransferToken();
+    method public android.os.IBinder? getWindowInputToken();
+    property @RequiresApi(android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM) public final android.window.InputTransferToken? inputTransferToken;
+    property public final android.os.IBinder? windowInputToken;
+    field public static final androidx.privacysandbox.ui.core.SessionConstants.Companion Companion;
+  }
+
+  public static final class SessionConstants.Companion {
+  }
+
   public interface SessionObserver {
     method public void onSessionClosed();
     method public void onSessionOpened(androidx.privacysandbox.ui.core.SessionObserverContext sessionObserverContext);
diff --git a/privacysandbox/ui/ui-core/api/restricted_current.txt b/privacysandbox/ui/ui-core/api/restricted_current.txt
index 313129f..8a52b96 100644
--- a/privacysandbox/ui/ui-core/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-core/api/restricted_current.txt
@@ -5,7 +5,7 @@
     ctor public DelegatingSandboxedUiAdapter(android.os.Bundle delegate);
     method public void addDelegateChangeListener(androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter.DelegateChangeListener listener);
     method public android.os.Bundle getDelegate();
-    method public void openSession(android.content.Context context, android.os.IBinder windowInputToken, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+    method public void openSession(android.content.Context context, androidx.privacysandbox.ui.core.SessionConstants sessionConstants, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
     method public void removeDelegateChangeListener(androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter.DelegateChangeListener listener);
     method public suspend Object? updateDelegate(android.os.Bundle delegate, kotlin.coroutines.Continuation<? super kotlin.Unit>);
   }
@@ -41,7 +41,7 @@
   }
 
   public interface SandboxedUiAdapter {
-    method public void openSession(android.content.Context context, android.os.IBinder windowInputToken, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+    method public void openSession(android.content.Context context, androidx.privacysandbox.ui.core.SessionConstants sessionConstants, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
   }
 
   public static interface SandboxedUiAdapter.Session extends java.lang.AutoCloseable {
@@ -70,6 +70,17 @@
     field public static final int apiVersion = 1; // 0x1
   }
 
+  public final class SessionConstants {
+    method public android.window.InputTransferToken? getInputTransferToken();
+    method public android.os.IBinder? getWindowInputToken();
+    property @RequiresApi(android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM) public final android.window.InputTransferToken? inputTransferToken;
+    property public final android.os.IBinder? windowInputToken;
+    field public static final androidx.privacysandbox.ui.core.SessionConstants.Companion Companion;
+  }
+
+  public static final class SessionConstants.Companion {
+  }
+
   public interface SessionObserver {
     method public void onSessionClosed();
     method public void onSessionOpened(androidx.privacysandbox.ui.core.SessionObserverContext sessionObserverContext);
diff --git a/privacysandbox/ui/ui-core/build.gradle b/privacysandbox/ui/ui-core/build.gradle
index f451589..a4690d0 100644
--- a/privacysandbox/ui/ui-core/build.gradle
+++ b/privacysandbox/ui/ui-core/build.gradle
@@ -48,6 +48,7 @@
     buildFeatures {
         aidl = true
     }
+    compileSdk 35
 }
 
 androidx {
diff --git a/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl
index 63aa0ac..69fbf09 100644
--- a/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl
+++ b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl
@@ -18,11 +18,12 @@
 
 import androidx.privacysandbox.ui.core.IRemoteSessionClient;
 import android.content.Context;
+import android.os.Bundle;
 
 @JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
 oneway interface ISandboxedUiAdapter {
     @JavaPassthrough(annotation="@androidx.annotation.RequiresApi(34)")
     void openRemoteSession(
-        IBinder hostToken, int displayId, int initialWidth, int initialHeight, boolean isZOrderOnTop,
+        in Bundle sessionConstants, int displayId, int initialWidth, int initialHeight, boolean isZOrderOnTop,
         IRemoteSessionClient remoteSessionClient);
 }
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/DelegatingSandboxedUiAdapter.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/DelegatingSandboxedUiAdapter.kt
index 3c0ad76..7e8cccb4 100644
--- a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/DelegatingSandboxedUiAdapter.kt
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/DelegatingSandboxedUiAdapter.kt
@@ -19,7 +19,6 @@
 import android.annotation.SuppressLint
 import android.content.Context
 import android.os.Bundle
-import android.os.IBinder
 import java.util.concurrent.CopyOnWriteArrayList
 import java.util.concurrent.Executor
 import kotlinx.coroutines.coroutineScope
@@ -71,7 +70,7 @@
 
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt
index d1b6995..23c219e 100644
--- a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.os.Bundle
-import android.os.IBinder
 import android.view.View
 import java.lang.AutoCloseable
 import java.util.concurrent.Executor
@@ -38,7 +37,7 @@
      */
     fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SessionConstants.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SessionConstants.kt
new file mode 100644
index 0000000..b54cc66
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SessionConstants.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.privacysandbox.ui.core
+
+import android.os.Build
+import android.os.Bundle
+import android.os.IBinder
+import android.window.InputTransferToken
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+
+/**
+ * A class containing values that will be constant for the lifetime of a
+ * [SandboxedUiAdapter.Session].
+ */
+class SessionConstants
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+constructor(
+    /**
+     * The input token of the window hosting this session.
+     *
+     * This value will be used when [Build.VERSION.SDK_INT] is equal to
+     * [Build.VERSION_CODES.UPSIDE_DOWN_CAKE].
+     */
+    val windowInputToken: IBinder?,
+    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    /**
+     * The input transfer token of the window hosting this session.
+     *
+     * This will be non-null when [Build.VERSION.SDK_INT] is greater than
+     * [Build.VERSION_CODES.UPSIDE_DOWN_CAKE].
+     */
+    val inputTransferToken: InputTransferToken?
+) {
+
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) constructor() : this(null, null)
+
+    companion object {
+        private const val KEY_WINDOW_INPUT_TOKEN = "windowInputToken"
+        private const val KEY_INPUT_TRANSFER_TOKEN = "inputTransferToken"
+
+        @JvmStatic
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        fun toBundle(sessionConstants: SessionConstants): Bundle {
+            val bundle = Bundle()
+            sessionConstants.windowInputToken?.let { bundle.putBinder(KEY_WINDOW_INPUT_TOKEN, it) }
+            CompatImpl.addInputTransferTokenToBundle(sessionConstants, bundle)
+            return bundle
+        }
+
+        @JvmStatic
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        fun fromBundle(bundle: Bundle): SessionConstants {
+            val windowInputToken = bundle.getBinder(KEY_WINDOW_INPUT_TOKEN)
+            val inputTransferToken = CompatImpl.deriveInputTransferToken(bundle)
+            return SessionConstants(windowInputToken, inputTransferToken)
+        }
+    }
+
+    override fun toString() =
+        "SessionConstants windowInputToken=$windowInputToken, inputTransferToken=$inputTransferToken"
+
+    override fun hashCode(): Int {
+        var result = windowInputToken.hashCode()
+        result += 31 * inputTransferToken.hashCode()
+        return result
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is SessionConstants) return false
+
+        return windowInputToken == other.windowInputToken &&
+            inputTransferToken == other.inputTransferToken
+    }
+
+    private object CompatImpl {
+
+        fun deriveInputTransferToken(bundle: Bundle): InputTransferToken? {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+                return Api35PlusImpl.deriveInputTransferToken(bundle)
+            } else {
+                return null
+            }
+        }
+
+        fun addInputTransferTokenToBundle(sessionConstants: SessionConstants, bundle: Bundle) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+                Api35PlusImpl.addInputTransferTokenToBundle(sessionConstants, bundle)
+            }
+        }
+
+        @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+        private object Api35PlusImpl {
+            fun deriveInputTransferToken(bundle: Bundle): InputTransferToken? {
+                return bundle.getParcelable(
+                    KEY_INPUT_TRANSFER_TOKEN,
+                    InputTransferToken::class.java
+                )
+            }
+
+            fun addInputTransferTokenToBundle(sessionConstants: SessionConstants, bundle: Bundle) {
+                bundle.putParcelable(KEY_INPUT_TRANSFER_TOKEN, sessionConstants.inputTransferToken)
+            }
+        }
+    }
+}
diff --git a/privacysandbox/ui/ui-provider/build.gradle b/privacysandbox/ui/ui-provider/build.gradle
index 0ebe484..e5c4b13 100644
--- a/privacysandbox/ui/ui-provider/build.gradle
+++ b/privacysandbox/ui/ui-provider/build.gradle
@@ -51,6 +51,7 @@
 
 android {
     namespace = "androidx.privacysandbox.ui.provider"
+    compileSdk 35
 }
 
 androidx {
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
index 697e3c8..c77b49c 100644
--- a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
@@ -23,7 +23,6 @@
 import android.os.Build
 import android.os.Bundle
 import android.os.Handler
-import android.os.IBinder
 import android.os.Looper
 import android.util.Log
 import android.view.Display
@@ -42,6 +41,7 @@
 import androidx.privacysandbox.ui.core.ProtocolConstants
 import androidx.privacysandbox.ui.core.RemoteCallManager.tryToCallRemoteObject
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.core.SessionObserver
 import androidx.privacysandbox.ui.core.SessionObserverContext
 import androidx.privacysandbox.ui.provider.impl.DeferredSessionClient
@@ -123,7 +123,7 @@
     /** Called in local mode via reflection. */
     override fun openSession(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
@@ -137,7 +137,7 @@
             val displayContext = sandboxContext.createDisplayContext(display)
             openSessionInternal(
                 displayContext,
-                windowInputToken,
+                sessionConstants,
                 initialWidth,
                 initialHeight,
                 isZOrderOnTop,
@@ -149,7 +149,7 @@
 
     /** Called in remote mode via binder call. */
     override fun openRemoteSession(
-        windowInputToken: IBinder,
+        sessionConstants: Bundle,
         displayId: Int,
         initialWidth: Int,
         initialHeight: Int,
@@ -162,7 +162,7 @@
             }
             return
         }
-
+        val constants = SessionConstants.fromBundle(sessionConstants)
         MainThreadExecutor.execute {
             try {
                 val displayManager =
@@ -173,10 +173,10 @@
                 val deferredClient =
                     DeferredSessionClient.create(
                         clientFactory = {
-                            Api34PlusImpl.createSessionClientProxy(
+                            RemoteCompatImpl.createSessionClientProxy(
                                 displayContext,
                                 display,
-                                windowInputToken,
+                                constants,
                                 isZOrderOnTop,
                                 remoteSessionClient
                             )
@@ -191,7 +191,7 @@
 
                 openSessionInternal(
                     displayContext,
-                    windowInputToken,
+                    constants,
                     initialWidth,
                     initialHeight,
                     isZOrderOnTop,
@@ -210,7 +210,7 @@
 
     private fun openSessionInternal(
         context: Context,
-        windowInputToken: IBinder,
+        sessionConstants: SessionConstants,
         initialWidth: Int,
         initialHeight: Int,
         isZOrderOnTop: Boolean,
@@ -219,7 +219,7 @@
     ) {
         adapter.openSession(
             context,
-            windowInputToken,
+            sessionConstants,
             initialWidth,
             initialHeight,
             isZOrderOnTop,
@@ -412,17 +412,28 @@
         }
     }
 
+    /**
+     * Provides backward compat support for APIs.
+     *
+     * If the API is available, it's called from a version-specific static inner class gated with
+     * version check, otherwise a fallback action is taken depending on the situation.
+     */
     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    private object Api34PlusImpl {
+    private object RemoteCompatImpl {
+
         fun createSessionClientProxy(
             displayContext: Context,
             display: Display,
-            windowInputToken: IBinder,
+            sessionConstants: SessionConstants,
             isZOrderOnTop: Boolean,
             remoteSessionClient: IRemoteSessionClient
         ): SessionClientProxy {
             val surfaceControlViewHost =
-                SurfaceControlViewHost(displayContext, display, windowInputToken)
+                checkNotNull(
+                    createSurfaceControlViewHost(displayContext, display, sessionConstants)
+                ) {
+                    "Failed to create SurfaceControlViewHost"
+                }
             val touchTransferringView =
                 TouchFocusTransferringView(displayContext, surfaceControlViewHost)
             return SessionClientProxy(
@@ -432,5 +443,50 @@
                 remoteSessionClient
             )
         }
+
+        fun createSurfaceControlViewHost(
+            displayContext: Context,
+            display: Display,
+            sessionConstants: SessionConstants
+        ): SurfaceControlViewHost? {
+            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+                Api35PlusImpl.createSurfaceControlViewHost(
+                    displayContext,
+                    display,
+                    sessionConstants
+                )
+            } else
+                Api34PlusImpl.createSurfaceControlViewHost(
+                    displayContext,
+                    display,
+                    sessionConstants
+                )
+        }
+
+        @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+        private object Api35PlusImpl {
+
+            @JvmStatic
+            fun createSurfaceControlViewHost(
+                context: Context,
+                display: Display,
+                sessionConstants: SessionConstants
+            ): SurfaceControlViewHost {
+                return SurfaceControlViewHost(context, display, sessionConstants.inputTransferToken)
+            }
+        }
+
+        @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+        private object Api34PlusImpl {
+
+            @JvmStatic
+            fun createSurfaceControlViewHost(
+                context: Context,
+                display: Display,
+                sessionConstants: SessionConstants
+            ): SurfaceControlViewHost {
+                return SurfaceControlViewHost(context, display, sessionConstants.windowInputToken)
+            }
+        }
     }
 }
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/TouchFocusTransferringView.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/TouchFocusTransferringView.kt
index a9e2182..d1d55a5 100644
--- a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/TouchFocusTransferringView.kt
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/TouchFocusTransferringView.kt
@@ -44,6 +44,7 @@
     private val scvh: SurfaceControlViewHost = surfaceControlViewHost
     private val detector = ScrollDetector(context)
 
+    @Suppress("deprecation") // transferTouchGestureToHost needs to be called on U- devices
     override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
         detector.onTouchEvent(ev)
         if (!detector.isScrolling) {
diff --git a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
index 4263899..3e24557 100644
--- a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
+++ b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/endtoend/IntegrationTests.kt
@@ -19,15 +19,19 @@
 import android.content.Context
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
+import android.os.Binder
+import android.os.Build
 import android.os.SystemClock
 import android.view.MotionEvent
 import android.view.View
 import android.view.View.OnLayoutChangeListener
 import android.view.ViewGroup
 import android.widget.LinearLayout
+import androidx.annotation.RequiresApi
 import androidx.privacysandbox.ui.client.view.SandboxedSdkView
 import androidx.privacysandbox.ui.core.SandboxedSdkViewUiInfo
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.integration.testingutils.TestEventListener
 import androidx.privacysandbox.ui.tests.endtoend.IntegrationTestSetupRule.Companion.INITIAL_HEIGHT
 import androidx.privacysandbox.ui.tests.endtoend.IntegrationTestSetupRule.Companion.INITIAL_WIDTH
@@ -138,7 +142,11 @@
 
     @Test
     fun testOpenSession_fromAdapter() {
-        val adapter = sessionManager.createAdapterAndEstablishSession(viewForSession = null)
+        val adapter =
+            sessionManager.createAdapterAndEstablishSession(
+                viewForSession = null,
+                sessionConstants = deriveSessionConstants()
+            )
         assertThat(adapter.session).isNotNull()
     }
 
@@ -526,4 +534,22 @@
                 )
         }
     }
+
+    private fun deriveSessionConstants(): SessionConstants {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+            return Api35PlusImpl.deriveSessionConstants(view)
+        } else {
+            return SessionConstants(windowInputToken = Binder(), inputTransferToken = null)
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    private object Api35PlusImpl {
+        fun deriveSessionConstants(view: SandboxedSdkView): SessionConstants {
+            return SessionConstants(
+                windowInputToken = Binder(),
+                inputTransferToken = view.rootSurfaceControl?.inputTransferToken
+            )
+        }
+    }
 }
diff --git a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/util/TestSessionManager.kt b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/util/TestSessionManager.kt
index b8e878c..ac65321 100644
--- a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/util/TestSessionManager.kt
+++ b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/util/TestSessionManager.kt
@@ -21,9 +21,7 @@
 import android.content.res.Configuration
 import android.graphics.Canvas
 import android.graphics.Color
-import android.os.Binder
 import android.os.Bundle
-import android.os.IBinder
 import android.view.Display
 import android.view.View
 import android.widget.FrameLayout
@@ -32,6 +30,7 @@
 import androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter
 import androidx.privacysandbox.ui.core.ExperimentalFeatures
 import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionConstants
 import androidx.privacysandbox.ui.core.SessionObserver
 import androidx.privacysandbox.ui.core.SessionObserverContext
 import androidx.privacysandbox.ui.core.SessionObserverFactory
@@ -69,7 +68,8 @@
         placeViewInsideFrameLayout: Boolean = false,
         viewForSession: SandboxedSdkView?,
         testSessionClient: TestSessionClient = TestSessionClient(),
-        sessionObserverFactories: List<SessionObserverFactory>? = null
+        sessionObserverFactories: List<SessionObserverFactory>? = null,
+        sessionConstants: SessionConstants = SessionConstants()
     ): TestSandboxedUiAdapter {
 
         val adapter = TestSandboxedUiAdapter(failToProvideUi, placeViewInsideFrameLayout)
@@ -81,7 +81,7 @@
         } else {
             adapterFromCoreLibInfo.openSession(
                 context,
-                windowInputToken = Binder(),
+                sessionConstants,
                 INITIAL_WIDTH,
                 INITIAL_HEIGHT,
                 isZOrderOnTop = true,
@@ -199,7 +199,7 @@
 
         override fun openSession(
             context: Context,
-            windowInputToken: IBinder,
+            sessionConstants: SessionConstants,
             initialWidth: Int,
             initialHeight: Int,
             isZOrderOnTop: Boolean,
diff --git a/room/room-common/api/api_lint.ignore b/room/room-common/api/api_lint.ignore
index 0f16720..934672f 100644
--- a/room/room-common/api/api_lint.ignore
+++ b/room/room-common/api/api_lint.ignore
@@ -1,8 +1,4 @@
 // Baseline format: 1.0
-AcronymName: androidx.room.ColumnInfo.SQLiteTypeAffinity:
-    Acronyms should not be capitalized in class names: was `SQLiteTypeAffinity`, should this be `SqLiteTypeAffinity`?
-
-
 GetterSetterNames: androidx.room.ColumnInfo#index:
     Invalid name for boolean property `index`. Should start with one of `has`, `can`, `should`, `is`.
 GetterSetterNames: androidx.room.Database#exportSchema:
diff --git a/room/room-common/build.gradle b/room/room-common/build.gradle
index 1cf5db4..e8eed4f 100644
--- a/room/room-common/build.gradle
+++ b/room/room-common/build.gradle
@@ -32,12 +32,14 @@
 }
 
 androidXMultiplatform {
+    js()
     jvm() {
         withJava()
     }
     mac()
     linux()
     ios()
+    wasmJs()
 
     defaultPlatform(PlatformIdentifier.JVM)
 
@@ -45,7 +47,7 @@
         commonMain {
             dependencies {
                 api(libs.kotlinStdlib)
-                api("androidx.annotation:annotation:1.8.1")
+                api("androidx.annotation:annotation:1.9.1")
             }
         }
 
diff --git a/room/room-common/src/jsMain/kotlin/androidx/room/ConstructedBy.js.kt b/room/room-common/src/jsMain/kotlin/androidx/room/ConstructedBy.js.kt
new file mode 100644
index 0000000..b43bd1e
--- /dev/null
+++ b/room/room-common/src/jsMain/kotlin/androidx/room/ConstructedBy.js.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.room
+
+import kotlin.reflect.AssociatedObjectKey
+import kotlin.reflect.ExperimentalAssociatedObjects
+import kotlin.reflect.KClass
+
+/**
+ * Defines the [androidx.room.RoomDatabaseConstructor] that will instantiate the Room generated
+ * implementation of the annotated [Database].
+ *
+ * A [androidx.room.RoomDatabase] database definition must be annotated with this annotation if it
+ * is located in a common source set on a Kotlin Multiplatform project such that at runtime the
+ * implementation generated by the annotation processor can be used. The [value] must be an 'expect
+ * object' that implements [androidx.room.RoomDatabaseConstructor].
+ *
+ * Example usage:
+ * ```
+ * @Database(version = 1, entities = [Song::class, Album::class])
+ * @ConstructedBy(MusicDatabaseConstructor::class)
+ * abstract class MusicDatabase : RoomDatabase
+ *
+ * expect object MusicDatabaseConstructor : RoomDatabaseConstructor<MusicDatabase>
+ * ```
+ *
+ * @see androidx.room.RoomDatabaseConstructor
+ */
+@OptIn(ExperimentalAssociatedObjects::class)
+@AssociatedObjectKey
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.BINARY)
+actual annotation class ConstructedBy(
+    /**
+     * The 'expect' declaration of an 'object' that implements
+     * [androidx.room.RoomDatabaseConstructor] and is able to instantiate a
+     * [androidx.room.RoomDatabase].
+     */
+    actual val value: KClass<*>
+)
diff --git a/room/room-common/src/wasmJsMain/kotlin/androidx/room/ConstructedBy.wasmJs.kt b/room/room-common/src/wasmJsMain/kotlin/androidx/room/ConstructedBy.wasmJs.kt
new file mode 100644
index 0000000..b43bd1e
--- /dev/null
+++ b/room/room-common/src/wasmJsMain/kotlin/androidx/room/ConstructedBy.wasmJs.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.room
+
+import kotlin.reflect.AssociatedObjectKey
+import kotlin.reflect.ExperimentalAssociatedObjects
+import kotlin.reflect.KClass
+
+/**
+ * Defines the [androidx.room.RoomDatabaseConstructor] that will instantiate the Room generated
+ * implementation of the annotated [Database].
+ *
+ * A [androidx.room.RoomDatabase] database definition must be annotated with this annotation if it
+ * is located in a common source set on a Kotlin Multiplatform project such that at runtime the
+ * implementation generated by the annotation processor can be used. The [value] must be an 'expect
+ * object' that implements [androidx.room.RoomDatabaseConstructor].
+ *
+ * Example usage:
+ * ```
+ * @Database(version = 1, entities = [Song::class, Album::class])
+ * @ConstructedBy(MusicDatabaseConstructor::class)
+ * abstract class MusicDatabase : RoomDatabase
+ *
+ * expect object MusicDatabaseConstructor : RoomDatabaseConstructor<MusicDatabase>
+ * ```
+ *
+ * @see androidx.room.RoomDatabaseConstructor
+ */
+@OptIn(ExperimentalAssociatedObjects::class)
+@AssociatedObjectKey
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.BINARY)
+actual annotation class ConstructedBy(
+    /**
+     * The 'expect' declaration of an 'object' that implements
+     * [androidx.room.RoomDatabaseConstructor] and is able to instantiate a
+     * [androidx.room.RoomDatabase].
+     */
+    actual val value: KClass<*>
+)
diff --git a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/compiler/Ksp2Compilation.kt b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/compiler/Ksp2Compilation.kt
index 4764bed..3d7aaa3 100644
--- a/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/compiler/Ksp2Compilation.kt
+++ b/room/room-compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/compiler/Ksp2Compilation.kt
@@ -62,7 +62,7 @@
                 diagnostics = kspDiagnostics.messages,
                 sourceSets = arguments.sourceSets + generatedSources
             )
-        val outputResources = workingDir.resolve(RESOURCES_OUT_FOLDER_NAME)
+        val outputResources = workingDir.resolve(RESOURCE_OUT_FOLDER_NAME)
         val outputClasspath = listOf(workingDir.resolve(CLASS_OUT_FOLDER_NAME))
         val generatedResources =
             outputResources
@@ -168,6 +168,5 @@
         private const val RESOURCE_OUT_FOLDER_NAME = "ksp-resource-out"
         private const val CACHE_FOLDER_NAME = "ksp-cache"
         private const val CLASS_OUT_FOLDER_NAME = "class-out"
-        private const val RESOURCES_OUT_FOLDER_NAME = "ksp-compiler/resourceOutputDir"
     }
 }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFilerTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFilerTest.kt
index 1753a3e..ab518b2 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFilerTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFilerTest.kt
@@ -169,19 +169,22 @@
 
     @Test
     fun writeResource() {
+        val logFileName = "test.log"
+        val serviceFileName = "META-INF/services/com.test.Foo"
         runKspTest(sources = emptyList()) { invocation ->
             invocation.processingEnv.filer
-                .writeResource(filePath = Path("test.log"), originatingElements = emptyList())
+                .writeResource(filePath = Path(logFileName), originatingElements = emptyList())
                 .bufferedWriter(Charsets.UTF_8)
                 .use { it.write("Hello!") }
             invocation.processingEnv.filer
-                .writeResource(
-                    filePath = Path("META-INF/services/com.test.Foo"),
-                    originatingElements = emptyList()
-                )
+                .writeResource(filePath = Path(serviceFileName), originatingElements = emptyList())
                 .bufferedWriter(Charsets.UTF_8)
                 .use { it.write("Not a real service...") }
-            invocation.assertCompilationResult { hasNoWarnings() }
+            invocation.assertCompilationResult {
+                generatedResourceFileWithPath(logFileName)
+                generatedResourceFileWithPath(serviceFileName)
+                hasNoWarnings()
+            }
         }
     }
 
diff --git a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
index 35104e8..cd0fa67 100644
--- a/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
+++ b/room/room-paging/src/androidMain/kotlin/androidx/room/paging/util/RoomPagingUtil.android.kt
@@ -31,7 +31,6 @@
  *
  * Any loaded data or queued loads prior to returning INVALID will be discarded
  */
-@get:Suppress("AcronymName")
 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public val INVALID: LoadResult<Any, Any> = LoadResult.Invalid<Any, Any>()
 
diff --git a/room/room-runtime/api/restricted_current.txt b/room/room-runtime/api/restricted_current.txt
index bb0324f..232e51e 100644
--- a/room/room-runtime/api/restricted_current.txt
+++ b/room/room-runtime/api/restricted_current.txt
@@ -203,20 +203,29 @@
   public abstract class RoomDatabase {
     ctor public RoomDatabase();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void assertNotMainThread();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void assertNotSuspendingTransaction();
     method @Deprecated public void beginTransaction();
     method @WorkerThread public abstract void clearAllTables();
     method public void close();
     method public androidx.sqlite.db.SupportSQLiteStatement compileStatement(String sql);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.List<androidx.room.migration.Migration> createAutoMigrations(java.util.Map<kotlin.reflect.KClass<? extends androidx.room.migration.AutoMigrationSpec>,? extends androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected androidx.room.RoomOpenDelegateMarker createOpenDelegate();
     method @Deprecated protected androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration config);
     method @Deprecated public void endTransaction();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @kotlin.jvm.JvmSuppressWildcards public java.util.List<androidx.room.migration.Migration> getAutoMigrations(java.util.Map<java.lang.Class<? extends androidx.room.migration.AutoMigrationSpec>,androidx.room.migration.AutoMigrationSpec> autoMigrationSpecs);
     method public androidx.room.InvalidationTracker getInvalidationTracker();
     method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected java.util.List<androidx.room.RoomDatabase.Callback>? getMCallbacks();
     method @Deprecated @kotlin.jvm.Volatile protected androidx.sqlite.db.SupportSQLiteDatabase? getMDatabase();
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.Set<kotlin.reflect.KClass<? extends androidx.room.migration.AutoMigrationSpec>> getRequiredAutoMigrationSpecClasses();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.Set<java.lang.Class<? extends androidx.room.migration.AutoMigrationSpec>> getRequiredAutoMigrationSpecs();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected java.util.Map<kotlin.reflect.KClass<? extends java.lang.Object?>,java.util.List<kotlin.reflect.KClass<? extends java.lang.Object?>>> getRequiredTypeConverterClasses();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected java.util.Map<java.lang.Class<? extends java.lang.Object?>,java.util.List<java.lang.Class<? extends java.lang.Object?>>> getRequiredTypeConverters();
     method public java.util.concurrent.Executor getTransactionExecutor();
     method @Deprecated public <T> T? getTypeConverter(Class<T> klass);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final <T> T getTypeConverter(kotlin.reflect.KClass<T> klass);
     method public boolean inTransaction();
     method @CallSuper public void init(androidx.room.DatabaseConfiguration configuration);
     method @Deprecated protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase db);
@@ -326,6 +335,31 @@
     method public static suspend <R> Object? withTransaction(androidx.room.RoomDatabase, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super R>,? extends java.lang.Object?> block, kotlin.coroutines.Continuation<? super R>);
   }
 
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class RoomOpenDelegate implements androidx.room.RoomOpenDelegateMarker {
+    ctor public RoomOpenDelegate(int version, String identityHash, String legacyIdentityHash);
+    method public abstract void createAllTables(androidx.sqlite.SQLiteConnection connection);
+    method public abstract void dropAllTables(androidx.sqlite.SQLiteConnection connection);
+    method public final String getIdentityHash();
+    method public final String getLegacyIdentityHash();
+    method public final int getVersion();
+    method public abstract void onCreate(androidx.sqlite.SQLiteConnection connection);
+    method public abstract void onOpen(androidx.sqlite.SQLiteConnection connection);
+    method public abstract void onPostMigrate(androidx.sqlite.SQLiteConnection connection);
+    method public abstract void onPreMigrate(androidx.sqlite.SQLiteConnection connection);
+    method public abstract androidx.room.RoomOpenDelegate.ValidationResult onValidateSchema(androidx.sqlite.SQLiteConnection connection);
+    property public final String identityHash;
+    property public final String legacyIdentityHash;
+    property public final int version;
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final class RoomOpenDelegate.ValidationResult {
+    ctor public RoomOpenDelegate.ValidationResult(boolean isValid, String? expectedFoundMsg);
+    property public final String? expectedFoundMsg;
+    property public final boolean isValid;
+    field public final String? expectedFoundMsg;
+    field public final boolean isValid;
+  }
+
   public interface RoomOpenDelegateMarker {
   }
 
diff --git a/room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java b/room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java
index 3cdc6c0..6e7b6a5 100644
--- a/room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java
+++ b/room/room-runtime/src/androidMain/java/androidx/room/paging/LimitOffsetDataSource.java
@@ -49,7 +49,7 @@
  *
  */
 @SuppressWarnings("deprecation")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 public abstract class LimitOffsetDataSource<T> extends androidx.paging.PositionalDataSource<T> {
     private final RoomSQLiteQuery mSourceQuery;
     private final String mCountQuery;
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
index 415065d..1544630 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/CoroutinesRoom.android.kt
@@ -29,7 +29,7 @@
 import kotlinx.coroutines.withContext
 
 /** A helper class for supporting Kotlin Coroutines in Room. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 public class CoroutinesRoom private constructor() {
 
     public companion object {
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
index 5329a272..c800d84 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/DatabaseConfiguration.android.kt
@@ -33,7 +33,7 @@
 @Suppress("UNUSED_PARAMETER")
 actual open class DatabaseConfiguration
 @SuppressLint("LambdaLast")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 constructor(
     /* The context to use while connecting to the database. */
     @JvmField val context: Context,
@@ -67,7 +67,7 @@
      *
      * @see [multiInstanceInvalidation]
      */
-    @field:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @field:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @JvmField
     val multiInstanceInvalidationServiceIntent: Intent?,
 
@@ -130,7 +130,7 @@
      * @param migrationNotRequiredFrom The collection of schema versions from which migrations
      *   aren't required.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -188,7 +188,7 @@
      *   aren't required.
      */
     @OptIn(ExperimentalRoomApi::class)
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -254,7 +254,7 @@
      * @param copyFromFile The pre-packaged database file.
      */
     @OptIn(ExperimentalRoomApi::class)
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -324,7 +324,7 @@
      *   database file will be copied from.
      */
     @OptIn(ExperimentalRoomApi::class)
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -397,7 +397,7 @@
      */
     @OptIn(ExperimentalRoomApi::class)
     @SuppressLint("LambdaLast")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -472,7 +472,7 @@
      */
     @OptIn(ExperimentalRoomApi::class)
     @SuppressLint("LambdaLast")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -549,7 +549,7 @@
      */
     @OptIn(ExperimentalRoomApi::class)
     @SuppressLint("LambdaLast")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -627,7 +627,7 @@
      * @param autoMigrationSpecs The auto migration specs.
      */
     @SuppressLint("LambdaLast")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
@@ -674,7 +674,7 @@
         queryCoroutineContext = null
     )
 
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated("This constructor is deprecated.")
     constructor(
         context: Context,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityDeletionOrUpdateAdapter.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityDeletionOrUpdateAdapter.android.kt
index 16ecdf8..a1a916e 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityDeletionOrUpdateAdapter.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityDeletionOrUpdateAdapter.android.kt
@@ -27,7 +27,7 @@
  * @constructor Creates a DeletionOrUpdateAdapter that can delete or update the entity type T on the
  *   given database.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 @Deprecated("No longer used by generated code.", ReplaceWith("EntityDeleteOrUpdateAdapter"))
 abstract class EntityDeletionOrUpdateAdapter<T>(database: RoomDatabase) :
     SharedSQLiteStatement(database) {
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityInsertionAdapter.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityInsertionAdapter.android.kt
index aa1be1a..0774ade 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityInsertionAdapter.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityInsertionAdapter.android.kt
@@ -27,7 +27,7 @@
  * @constructor Creates an InsertionAdapter that can insert the entity type T into the given
  *   database.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 @Deprecated("No longer used by generated code.", ReplaceWith("EntityInsertAdapter"))
 abstract class EntityInsertionAdapter<T>(database: RoomDatabase) : SharedSQLiteStatement(database) {
     /**
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityUpsertionAdapter.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityUpsertionAdapter.android.kt
index bc8c8f2..9d30a08 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityUpsertionAdapter.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/EntityUpsertionAdapter.android.kt
@@ -42,7 +42,7 @@
  *   using the given insertionAdapter to perform insertion and updateAdapter to perform update when
  *   the insertion fails
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 @Deprecated("No longer used by generated code.", ReplaceWith("EntityUpsertAdapter"))
 class EntityUpsertionAdapter<T>(
     @Suppress("DEPRECATION") private val insertionAdapter: EntityInsertionAdapter<T>,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
index 9b5e5d8..0454358 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/InvalidationTracker.android.kt
@@ -47,7 +47,7 @@
  * new value.
  */
 actual open class InvalidationTracker
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual constructor(
     internal val database: RoomDatabase,
     private val shadowTablesMap: Map<String, String>,
@@ -91,7 +91,7 @@
     private val trackerLock = Any()
 
     @Deprecated("No longer called by generated implementation")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     constructor(
         database: RoomDatabase,
         vararg tableNames: String
@@ -290,7 +290,7 @@
      * @param observer The observer to which InvalidationTracker will keep a weak reference.
      */
     @WorkerThread
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun addWeakObserver(observer: Observer) {
         addObserver(WeakObserver(this, observer))
     }
@@ -340,7 +340,7 @@
      * @see refresh
      */
     @WorkerThread
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun refreshVersionsSync(): Unit = runBlocking {
         implementation.refreshInvalidation(emptyArray(), onRefreshScheduled, onRefreshCompleted)
     }
@@ -381,7 +381,7 @@
      * @return A new LiveData that computes the given function when the given list of tables
      *   invalidates.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Deprecated(
         message = "Replaced with overload that takes 'inTransaction 'parameter.",
         replaceWith = ReplaceWith("createLiveData(tableNames, false, computeFunction")
@@ -407,7 +407,7 @@
      * @return A new LiveData that computes the given function when the given list of tables
      *   invalidates.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun <T> createLiveData(
         tableNames: Array<out String>,
         inTransaction: Boolean,
@@ -433,7 +433,7 @@
      * @return A new LiveData that computes the given function when the given list of tables
      *   invalidates.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     fun <T> createLiveData(
         tableNames: Array<out String>,
         inTransaction: Boolean,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
index c72e4e6..1152eef 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomDatabase.android.kt
@@ -154,7 +154,7 @@
         message = "This property is always null and will be removed in a future version.",
         level = DeprecationLevel.ERROR
     )
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected var mCallbacks: List<Callback>? = null
 
     private var autoCloser: AutoCloser? = null
@@ -193,7 +193,7 @@
      * @param T The type of the expected Type Converter subclass.
      * @return An instance of T.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Suppress("UNCHECKED_CAST")
     actual fun <T : Any> getTypeConverter(klass: KClass<T>): T {
         return typeConverters[klass] as T
@@ -320,7 +320,7 @@
      * @return A list of migration instances each of which is a generated autoMigration
      */
     @Deprecated("No longer implemented by generated")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @JvmSuppressWildcards // Suppress wildcards due to generated Java code
     open fun getAutoMigrations(
         autoMigrationSpecs: Map<Class<out AutoMigrationSpec>, AutoMigrationSpec>
@@ -328,7 +328,7 @@
         return emptyList()
     }
 
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual open fun createAutoMigrations(
         autoMigrationSpecs: Map<KClass<out AutoMigrationSpec>, AutoMigrationSpec>
     ): List<Migration> {
@@ -386,7 +386,7 @@
      * @return A new delegate to be used while opening the database
      * @throws NotImplementedError by default
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual open fun createOpenDelegate(): RoomOpenDelegateMarker {
         throw NotImplementedError()
     }
@@ -424,7 +424,7 @@
      *
      * @return Creates a map that will include all required type converters for this database.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected open fun getRequiredTypeConverters(): Map<Class<*>, List<Class<*>>> {
         return emptyMap()
     }
@@ -439,7 +439,7 @@
      *
      * @return A map that will include all required type converters for this database.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual open fun getRequiredTypeConverterClasses(): Map<KClass<*>, List<KClass<*>>> {
         // For backwards compatibility when newer runtime is used with older generated code,
         // call the Java version this function.
@@ -460,12 +460,12 @@
      * @return Creates a set that will include all required auto migration specs for this database.
      */
     @Deprecated("No longer implemented by generated")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun getRequiredAutoMigrationSpecs(): Set<Class<out AutoMigrationSpec>> {
         return emptySet()
     }
 
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual open fun getRequiredAutoMigrationSpecClasses(): Set<KClass<out AutoMigrationSpec>> {
         // For backwards compatibility when newer runtime is used with older generated code,
         // call the Java version of this function.
@@ -565,7 +565,7 @@
     }
 
     /** Asserts that we are not on a suspending transaction. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // used in generated code
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun assertNotSuspendingTransaction() {
         check(!inCompatibilityMode() || inTransaction() || suspendingTransactionId.get() == null) {
             "Cannot access database on a different coroutine" +
@@ -755,7 +755,7 @@
      *
      * @param connection The database connection.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual fun internalInitInvalidationTracker(connection: SQLiteConnection) {
         invalidationTracker.internalInit(connection)
     }
@@ -1931,7 +1931,8 @@
         /**
          * Unfortunately, we cannot read this value so we are only setting it to the SQLite default.
          */
-        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) const val MAX_BIND_PARAMETER_CNT = 999
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
+        const val MAX_BIND_PARAMETER_CNT = 999
     }
 }
 
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomOpenHelper.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomOpenHelper.android.kt
index 4ba4223..af2f515 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomOpenHelper.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomOpenHelper.android.kt
@@ -25,7 +25,7 @@
 /** An open helper that holds a reference to the configuration until the database is opened. */
 @Suppress("DEPRECATION") // Due to usage of RoomOpenHelper.Delegate
 @Deprecated("Replaced by RoomConnectionManager and no longer used in generated code.")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 open class RoomOpenHelper(
     configuration: DatabaseConfiguration,
     delegate: Delegate,
@@ -180,7 +180,7 @@
     }
 
     @Deprecated("Replaced by OpenDelegate  and no longer used in generated code.")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     abstract class Delegate(@JvmField val version: Int) {
         abstract fun dropAllTables(db: SupportSQLiteDatabase)
 
@@ -227,7 +227,7 @@
     }
 
     @Deprecated("Replaced by OpenDelegate.ValidationResult and no longer used in generated code.")
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open class ValidationResult(
         @JvmField val isValid: Boolean,
         @JvmField val expectedFoundMsg: String?
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomSQLiteQuery.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomSQLiteQuery.android.kt
index e88a1cd..f8b7203 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomSQLiteQuery.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/RoomSQLiteQuery.android.kt
@@ -31,7 +31,7 @@
  * Because it is relatively a big object, they are pooled and must be released after each use.
  */
 @SuppressLint("WrongConstant")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 class RoomSQLiteQuery private constructor(@field:VisibleForTesting val capacity: Int) :
     SupportSQLiteQuery, SupportSQLiteProgram {
     @Volatile private var query: String? = null
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/SharedSQLiteStatement.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/SharedSQLiteStatement.android.kt
index df05367..052c3aa 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/SharedSQLiteStatement.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/SharedSQLiteStatement.android.kt
@@ -31,7 +31,7 @@
  * @constructor Creates an SQLite prepared statement that can be re-used across threads. If it is in
  *   use, it automatically creates a new one.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 abstract class SharedSQLiteStatement(private val database: RoomDatabase) {
     private val lock = AtomicBoolean(false)
 
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
index 58dce9f..01dc16b 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/support/QueryInterceptorDatabase.android.kt
@@ -111,17 +111,11 @@
         return delegate.query(query)
     }
 
-    // Suppress warning about `SQL` in execSQL not being camel case. This is an override function
-    // and it can't be renamed.
-    @Suppress("AcronymName")
     override fun execSQL(sql: String) {
         queryCallbackScope.launch { queryCallback.onQuery(sql, emptyList()) }
         delegate.execSQL(sql)
     }
 
-    // Suppress warning about `SQL` in execSQL not being camel case. This is an override function
-    // and it can't be renamed.
-    @Suppress("AcronymName")
     override fun execSQL(sql: String, bindArgs: Array<out Any?>) {
         val argsCopy = bindArgs.toList()
         queryCallbackScope.launch { queryCallback.onQuery(sql, argsCopy) }
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
index 8bb4ef8..34c07eb 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 @file:JvmName("CursorUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 
 package androidx.room.util
 
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/DBUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/DBUtil.android.kt
index 7faeb6a..ec520d9 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/DBUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/DBUtil.android.kt
@@ -42,7 +42,7 @@
 import kotlinx.coroutines.withContext
 
 /** Performs a database operation. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual suspend fun <R> performSuspending(
     db: RoomDatabase,
     isReadOnly: Boolean,
@@ -57,7 +57,7 @@
     }
 
 /** Blocking version of [performSuspending] */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <R> performBlocking(
     db: RoomDatabase,
     isReadOnly: Boolean,
@@ -80,7 +80,7 @@
  * This function should only be invoked from generated code and is needed to support `@Transaction`
  * delegates in Java and Kotlin. It is preferred to use the other 'perform' functions.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual suspend fun <R> performInTransactionSuspending(db: RoomDatabase, block: suspend () -> R): R =
     if (db.inCompatibilityMode()) {
         db.withTransactionContext {
@@ -138,7 +138,7 @@
  * @return Result of the query.
  */
 @Deprecated("This is only used in the generated code and shouldn't be called directly.")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun query(db: RoomDatabase, sqLiteQuery: SupportSQLiteQuery, maybeCopy: Boolean): Cursor {
     return query(db, sqLiteQuery, maybeCopy, null)
 }
@@ -156,7 +156,7 @@
  * @param signal The cancellation signal to be attached to the query.
  * @return Result of the query.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun query(
     db: RoomDatabase,
     sqLiteQuery: SupportSQLiteQuery,
@@ -188,13 +188,13 @@
  * @param db The database.
  */
 @Deprecated("Replaced by dropFtsSyncTriggers(connection: SQLiteConnection)")
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun dropFtsSyncTriggers(db: SupportSQLiteDatabase) {
     dropFtsSyncTriggers(SupportSQLiteConnection(db))
 }
 
 /** Checks for foreign key violations by executing a PRAGMA foreign_key_check. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun foreignKeyCheck(db: SupportSQLiteDatabase, tableName: String) {
     foreignKeyCheck(SupportSQLiteConnection(db), tableName)
 }
@@ -208,7 +208,7 @@
  *   missing permissions.
  * @see [User Version Number](https://www.sqlite.org/fileformat.html.user_version_number).
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 @Throws(IOException::class)
 fun readVersion(databaseFile: File): Int {
     FileInputStream(databaseFile).channel.use { input ->
@@ -230,12 +230,12 @@
  * @return A new instance of CancellationSignal.
  */
 @Deprecated("Use constructor", ReplaceWith("CancellationSignal()", "android.os.CancellationSignal"))
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun createCancellationSignal(): CancellationSignal {
     return CancellationSignal()
 }
 
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun toSQLiteConnection(db: SupportSQLiteDatabase): SQLiteConnection {
     return SupportSQLiteConnection(db)
 }
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FileUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FileUtil.android.kt
index 89ca2d8..2caff1f 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FileUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FileUtil.android.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 @file:JvmName("FileUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 
 package androidx.room.util
 
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FtsTableInfo.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FtsTableInfo.android.kt
index 5f12aa9..60a9f04 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FtsTableInfo.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/FtsTableInfo.android.kt
@@ -21,7 +21,7 @@
 import androidx.sqlite.db.SupportSQLiteDatabase
 
 /** A data class that holds the information about an FTS table. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class FtsTableInfo(
     /** The table name */
     @JvmField actual val name: String,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
index 1ea7240..76af3114 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/RelationUtil.android.kt
@@ -31,7 +31,7 @@
  * @param isRelationCollection - True if [V] is a [Collection] which means it is non null.
  * @param fetchBlock - A lambda for calling the generated _fetchRelationship function.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <K : Any, V> recursiveFetchHashMap(
     map: HashMap<K, V>,
     isRelationCollection: Boolean,
@@ -71,7 +71,7 @@
 }
 
 /** Same as [recursiveFetchHashMap] but for [ArrayMap]. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <K : Any, V> recursiveFetchArrayMap(
     map: ArrayMap<K, V>,
     isRelationCollection: Boolean,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/TableInfo.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/TableInfo.android.kt
index bc9b664..fdf5756 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/TableInfo.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/TableInfo.android.kt
@@ -31,7 +31,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class TableInfo
 actual constructor(
     /** The table name. */
@@ -102,7 +102,7 @@
     }
 
     /** Holds the information about a database column. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class Column
     actual constructor(
         /** The column name. */
@@ -153,7 +153,7 @@
     }
 
     /** Holds the information about an SQLite foreign key */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class ForeignKey
     actual constructor(
         @JvmField actual val referenceTable: String,
@@ -170,7 +170,7 @@
     }
 
     /** Holds the information about an SQLite index */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class Index
     actual constructor(
         @JvmField actual val name: String,
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/ViewInfo.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/ViewInfo.android.kt
index 41fa707..b5e1448 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/ViewInfo.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/ViewInfo.android.kt
@@ -27,7 +27,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class ViewInfo
 actual constructor(
     /** The view name */
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityDeleteOrUpdateAdapter.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityDeleteOrUpdateAdapter.kt
index 871f7d5..01c0402 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityDeleteOrUpdateAdapter.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityDeleteOrUpdateAdapter.kt
@@ -29,7 +29,7 @@
  * @constructor Creates a DeletionOrUpdateAdapter that can delete or update the entity type T on the
  *   given database.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 abstract class EntityDeleteOrUpdateAdapter<T> {
     /**
      * Create the deletion or update query
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityInsertAdapter.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityInsertAdapter.kt
index e9d7bfe..743ee70 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityInsertAdapter.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityInsertAdapter.kt
@@ -29,7 +29,7 @@
  * @constructor Creates an InsertionAdapter that can insert the entity type T into the given
  *   database.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 abstract class EntityInsertAdapter<T> {
     /**
      * Create the query.
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityUpsertAdapter.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityUpsertAdapter.kt
index 3bbb3a9..9dd5110 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityUpsertAdapter.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/EntityUpsertAdapter.kt
@@ -29,7 +29,7 @@
  *   using the given insertionAdapter to perform insertion and updateAdapter to perform update when
  *   the insertion fails
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 class EntityUpsertAdapter<T>(
     private val entityInsertAdapter: EntityInsertAdapter<T>,
     private val updateAdapter: EntityDeleteOrUpdateAdapter<T>
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
index 5730b60..f958350 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/InvalidationTracker.kt
@@ -46,7 +46,7 @@
  * created from, then such table is considered 'invalidated' and the [Flow] will emit a new value.
  */
 expect class InvalidationTracker
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 constructor(
     database: RoomDatabase,
     shadowTablesMap: Map<String, String>,
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
index 1dbaafd..ae3a382 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomDatabase.kt
@@ -89,7 +89,7 @@
      *
      * @return A new delegate to be used while opening the database
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected open fun createOpenDelegate(): RoomOpenDelegateMarker
 
     /**
@@ -113,7 +113,7 @@
      * @return Creates a set that will include the classes of all required auto migration specs for
      *   this database.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun getRequiredAutoMigrationSpecClasses(): Set<KClass<out AutoMigrationSpec>>
 
     /**
@@ -125,7 +125,7 @@
      * @param autoMigrationSpecs the provided specs needed by certain migrations.
      * @return A list of migration instances each of which is a generated 'auto migration'.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     open fun createAutoMigrations(
         autoMigrationSpecs: Map<KClass<out AutoMigrationSpec>, AutoMigrationSpec>
     ): List<Migration>
@@ -139,7 +139,8 @@
      * @param T The type of the expected Type Converter subclass.
      * @return An instance of T.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) fun <T : Any> getTypeConverter(klass: KClass<T>): T
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
+    fun <T : Any> getTypeConverter(klass: KClass<T>): T
 
     /**
      * Adds a provided type converter to be used in the database DAOs.
@@ -159,7 +160,7 @@
      *
      * @return A map that will include all required type converters for this database.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected open fun getRequiredTypeConverterClasses(): Map<KClass<*>, List<KClass<*>>>
 
     /** Property delegate of [getRequiredTypeConverterClasses] for common ext functionality. */
@@ -171,7 +172,7 @@
      *
      * @param connection The database connection.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected fun internalInitInvalidationTracker(connection: SQLiteConnection)
 
     /**
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
index 9c3d501..9fd2bf6 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/RoomOpenDelegate.kt
@@ -27,9 +27,9 @@
  * implementation of a RoomDatabase with runtime.
  *
  * @see [RoomDatabase.createOpenDelegate]
- * @see [RoomConnectionManager.openDelegate]
+ * @see [BaseRoomConnectionManager.openDelegate]
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 abstract class RoomOpenDelegate(
     val version: Int,
     val identityHash: String,
@@ -49,7 +49,7 @@
 
     abstract fun dropAllTables(connection: SQLiteConnection)
 
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     class ValidationResult(@JvmField val isValid: Boolean, @JvmField val expectedFoundMsg: String?)
 }
 
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
index 105f220..7ba38d0 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/Transactor.kt
@@ -42,7 +42,6 @@
 }
 
 /** Executes a single SQL statement that returns no values. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 suspend fun PooledConnection.execSQL(sql: String) {
     usePrepared(sql) { it.step() }
 }
@@ -78,7 +77,6 @@
      *
      * @see Transactor.withTransaction
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
     enum class SQLiteTransactionType {
         /**
          * The transaction mode that does not start the actual transaction until the database is
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt
index 3fdf0d1..526454f 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/coroutines/FlowBuilder.kt
@@ -27,7 +27,7 @@
 import kotlinx.coroutines.flow.conflate
 import kotlinx.coroutines.flow.map
 
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <R> createFlow(
     db: RoomDatabase,
     inTransaction: Boolean,
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ByteArrayWrapper.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ByteArrayWrapper.kt
index cdb18cb..f4a10bd 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ByteArrayWrapper.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ByteArrayWrapper.kt
@@ -19,7 +19,7 @@
 import kotlin.jvm.JvmField
 
 /** A [ByteArray] wrapper that implements equals and hashCode to be used as a Map key.typ */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 class ByteArrayWrapper(@JvmField val array: ByteArray) {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ConnectionUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ConnectionUtil.kt
index e9f7bc5..7a3512f 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ConnectionUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ConnectionUtil.kt
@@ -30,7 +30,7 @@
  * See (official SQLite documentation)[http://www.sqlite.org/lang_corefunc.html#last_insert_rowid]
  * for details.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun getLastInsertedRowId(connection: SQLiteConnection): Long {
     if (getTotalChangedRows(connection) == 0) {
         return -1
@@ -48,7 +48,7 @@
  * See the (official SQLite documentation)[http://www.sqlite.org/lang_corefunc.html#changes] for
  * details.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun getTotalChangedRows(connection: SQLiteConnection): Int {
     return connection.prepare("SELECT changes()").use {
         it.step()
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/DBUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/DBUtil.kt
index b15c5f3..2c031c6 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/DBUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/DBUtil.kt
@@ -32,7 +32,7 @@
 import kotlin.jvm.JvmName
 
 /** Performs a database operation. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 expect suspend fun <R> performSuspending(
     db: RoomDatabase,
     isReadOnly: Boolean,
@@ -82,7 +82,7 @@
  * delegates in Java and Kotlin. It is preferred to use the other 'perform' functions.
  */
 // TODO(b/309996304): Replace with proper suspending transaction API for common.
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 expect suspend fun <R> performInTransactionSuspending(db: RoomDatabase, block: suspend () -> R): R
 
 /**
@@ -93,7 +93,7 @@
  *
  * @param connection The database connection.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun dropFtsSyncTriggers(connection: SQLiteConnection) {
     val existingTriggers = buildList {
         connection.prepare("SELECT name FROM sqlite_master WHERE type = 'trigger'").use {
@@ -111,7 +111,7 @@
 }
 
 /** Checks for foreign key violations by executing a PRAGMA foreign_key_check. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun foreignKeyCheck(db: SQLiteConnection, tableName: String) {
     db.prepare("PRAGMA foreign_key_check(`$tableName`)").use { stmt ->
         if (stmt.step()) {
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/FtsTableInfo.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/FtsTableInfo.kt
index f6fffde..dcec8e2 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/FtsTableInfo.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/FtsTableInfo.kt
@@ -21,7 +21,7 @@
 import kotlin.jvm.JvmStatic
 
 /** A data class that holds the information about an FTS table. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 expect class FtsTableInfo {
     /** The table name */
     val name: String
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt
index 828c589..1b85296 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/RelationUtil.kt
@@ -32,7 +32,7 @@
  * @param isRelationCollection - True if [V] is a [Collection] which means it is non null.
  * @param fetchBlock - A lambda for calling the generated _fetchRelationship function.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <K : Any, V> recursiveFetchMap(
     map: MutableMap<K, V>,
     isRelationCollection: Boolean,
@@ -72,7 +72,7 @@
 }
 
 /** Same as [recursiveFetchMap] but for [LongSparseArray]. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <V> recursiveFetchLongSparseArray(
     map: LongSparseArray<V>,
     isRelationCollection: Boolean,
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
index 7272ad6..211017e 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StatementUtil.kt
@@ -28,7 +28,7 @@
  * Returns the zero-based index for the given column name, or throws [IllegalArgumentException] if
  * the column doesn't exist.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun getColumnIndexOrThrow(stmt: SQLiteStatement, name: String): Int {
     val index: Int = stmt.columnIndexOf(name)
     if (index >= 0) {
@@ -56,7 +56,7 @@
 }
 
 /** Returns the zero-based index for the given column name, or -1 if the column doesn't exist. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun getColumnIndex(stmt: SQLiteStatement, name: String): Int {
     return stmt.columnIndexOf(name)
 }
@@ -76,7 +76,7 @@
  * @param mapping the cursor column indices of the columns at `columnNames`.
  * @return the wrapped Cursor.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun wrapMappedColumns(
     statement: SQLiteStatement,
     columnNames: Array<String>,
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StringUtil.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StringUtil.kt
index cd65582..fedd164 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StringUtil.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/StringUtil.kt
@@ -15,7 +15,7 @@
  */
 
 @file:JvmName("StringUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 
 package androidx.room.util
 
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/TableInfo.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/TableInfo.kt
index 2ac97ab..427f035 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/TableInfo.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/TableInfo.kt
@@ -29,7 +29,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 expect class TableInfo(
     name: String,
     columns: Map<String, Column>,
@@ -75,7 +75,7 @@
     }
 
     /** Holds the information about a database column. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     class Column(
         name: String,
         type: String,
@@ -117,7 +117,7 @@
     }
 
     /** Holds the information about an SQLite foreign key */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     class ForeignKey(
         referenceTable: String,
         onDelete: String,
@@ -139,7 +139,7 @@
     }
 
     /** Holds the information about an SQLite index */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     class Index(name: String, unique: Boolean, columns: List<String>, orders: List<String>) {
 
         val name: String
diff --git a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ViewInfo.kt b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ViewInfo.kt
index 0f80341..a0486cd 100644
--- a/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ViewInfo.kt
+++ b/room/room-runtime/src/commonMain/kotlin/androidx/room/util/ViewInfo.kt
@@ -26,7 +26,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 expect class ViewInfo(name: String, sql: String?) {
     /** The view name */
     val name: String
diff --git a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/KClassUtil.jvmAndroid.kt b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/KClassUtil.jvmAndroid.kt
index 5f7b12e..ec3aeaf 100644
--- a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/KClassUtil.jvmAndroid.kt
+++ b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/KClassUtil.jvmAndroid.kt
@@ -15,7 +15,7 @@
  */
 
 @file:JvmName("KClassUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 
 package androidx.room.util
 
@@ -25,7 +25,7 @@
  * Finds and instantiates via reflection the implementation class generated by Room of an
  * `@Database` annotated type.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <T, C> findAndInstantiateDatabaseImpl(klass: Class<C>, suffix: String = "_Impl"): T {
     val fullPackage: String = klass.getPackage()?.name ?: ""
     val name: String = klass.canonicalName!!
diff --git a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/UUIDUtil.jvmAndroid.kt b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/UUIDUtil.jvmAndroid.kt
index 8191d4e..3040ce9 100644
--- a/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/UUIDUtil.jvmAndroid.kt
+++ b/room/room-runtime/src/jvmAndroidMain/kotlin/androidx/room/util/UUIDUtil.jvmAndroid.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 @file:JvmName("UUIDUtil")
-@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 
 package androidx.room.util
 
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/InvalidationTracker.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/InvalidationTracker.jvmNative.kt
index 64020fb..cffa497 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/InvalidationTracker.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/InvalidationTracker.jvmNative.kt
@@ -31,7 +31,7 @@
  * created from, then such table is considered 'invalidated' and the [Flow] will emit a new value.
  */
 actual class InvalidationTracker
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual constructor(
     private val database: RoomDatabase,
     shadowTablesMap: Map<String, String>,
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
index ba4a415..5d56a72 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/RoomDatabase.jvmNative.kt
@@ -117,7 +117,7 @@
      * @return A new delegate to be used while opening the database
      * @throws NotImplementedError by default
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual open fun createOpenDelegate(): RoomOpenDelegateMarker {
         throw NotImplementedError()
     }
@@ -147,7 +147,7 @@
      *   this database.
      * @throws NotImplementedError by default
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual open fun getRequiredAutoMigrationSpecClasses(): Set<KClass<out AutoMigrationSpec>> {
         throw NotImplementedError()
     }
@@ -162,7 +162,7 @@
      * @return A list of migration instances each of which is a generated 'auto migration'.
      * @throws NotImplementedError by default
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual open fun createAutoMigrations(
         autoMigrationSpecs: Map<KClass<out AutoMigrationSpec>, AutoMigrationSpec>
     ): List<Migration> {
@@ -178,7 +178,7 @@
      * @param T The type of the expected Type Converter subclass.
      * @return An instance of T.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     @Suppress("UNCHECKED_CAST")
     actual fun <T : Any> getTypeConverter(klass: KClass<T>): T {
         return typeConverters[klass] as T
@@ -204,7 +204,7 @@
      *
      * @return A map that will include all required type converters for this database.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual open fun getRequiredTypeConverterClasses(): Map<KClass<*>, List<KClass<*>>> {
         throw NotImplementedError()
     }
@@ -219,7 +219,7 @@
      *
      * @param connection The database connection.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     protected actual fun internalInitInvalidationTracker(connection: SQLiteConnection) {
         invalidationTracker.internalInit(connection)
     }
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/DBUtil.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/DBUtil.jvmNative.kt
index a60784a..61e53f1 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/DBUtil.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/DBUtil.jvmNative.kt
@@ -29,7 +29,7 @@
 import kotlinx.coroutines.withContext
 
 /** Performs a database operation. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual suspend fun <R> performSuspending(
     db: RoomDatabase,
     isReadOnly: Boolean,
@@ -58,7 +58,7 @@
  * This function should only be invoked from generated code and is needed to support `@Transaction`
  * delegates in Java and Kotlin. It is preferred to use the other 'perform' functions.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual suspend fun <R> performInTransactionSuspending(db: RoomDatabase, block: suspend () -> R): R =
     withContext(db.getCoroutineContext(inTransaction = true)) {
         db.internalPerform(isReadOnly = false, inTransaction = true) { block.invoke() }
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/FtsTableInfo.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/FtsTableInfo.jvmNative.kt
index 8d60b9a..b315548 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/FtsTableInfo.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/FtsTableInfo.jvmNative.kt
@@ -21,7 +21,7 @@
 import kotlin.jvm.JvmStatic
 
 /** A data class that holds the information about an FTS table. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class FtsTableInfo(
     /** The table name */
     @JvmField actual val name: String,
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/TableInfo.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/TableInfo.jvmNative.kt
index 7bfa4b1..5c5a8b7 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/TableInfo.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/TableInfo.jvmNative.kt
@@ -30,7 +30,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class TableInfo
 actual constructor(
     /** The table name. */
@@ -80,7 +80,7 @@
     }
 
     /** Holds the information about a database column. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class Column
     actual constructor(
         /** The column name. */
@@ -117,7 +117,7 @@
     }
 
     /** Holds the information about an SQLite foreign key */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class ForeignKey
     actual constructor(
         actual val referenceTable: String,
@@ -134,7 +134,7 @@
     }
 
     /** Holds the information about an SQLite index */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
     actual class Index
     actual constructor(
         actual val name: String,
diff --git a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/ViewInfo.jvmNative.kt b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/ViewInfo.jvmNative.kt
index 60e07e7..a31fac8 100644
--- a/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/ViewInfo.jvmNative.kt
+++ b/room/room-runtime/src/jvmNativeMain/kotlin/androidx/room/util/ViewInfo.jvmNative.kt
@@ -26,7 +26,7 @@
  *
  * Even though SQLite column names are case insensitive, this class uses case sensitive matching.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 actual class ViewInfo
 actual constructor(
     /** The view name */
diff --git a/room/room-runtime/src/nativeMain/kotlin/androidx/room/util/KClassUtil.native.kt b/room/room-runtime/src/nativeMain/kotlin/androidx/room/util/KClassUtil.native.kt
index 3be16d4..0a3ccce 100644
--- a/room/room-runtime/src/nativeMain/kotlin/androidx/room/util/KClassUtil.native.kt
+++ b/room/room-runtime/src/nativeMain/kotlin/androidx/room/util/KClassUtil.native.kt
@@ -32,7 +32,7 @@
  * annotated type.
  */
 @OptIn(ExperimentalAssociatedObjects::class)
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) // used in generated code
 fun <T : RoomDatabase> findDatabaseConstructorAndInitDatabaseImpl(klass: KClass<*>): T {
     val constructor = klass.findAssociatedObject<ConstructedBy>() as? RoomDatabaseConstructor<*>
     checkNotNull(constructor) {
diff --git a/savedstate/savedstate/api/current.txt b/savedstate/savedstate/api/current.txt
index 8a63bfe..2c7e9e3d 100644
--- a/savedstate/savedstate/api/current.txt
+++ b/savedstate/savedstate/api/current.txt
@@ -169,10 +169,8 @@
   }
 
   public final class SavedStateRegistryOwnerDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
@@ -219,6 +217,11 @@
     property public final kotlinx.serialization.descriptors.SerialDescriptor descriptor;
   }
 
+  public final class MutableStateFlowSerializerKt {
+    method public static inline <reified T> kotlinx.serialization.KSerializer<kotlinx.coroutines.flow.MutableStateFlow<T>> MutableStateFlowSerializer();
+    method public static <T> kotlinx.serialization.KSerializer<kotlinx.coroutines.flow.MutableStateFlow<T>> MutableStateFlowSerializer(kotlinx.serialization.KSerializer<T> serializer);
+  }
+
   public final class ParcelableArraySerializer implements kotlinx.serialization.KSerializer<android.os.Parcelable[]> {
     ctor public ParcelableArraySerializer();
     method public android.os.Parcelable[] deserialize(kotlinx.serialization.encoding.Decoder decoder);
diff --git a/savedstate/savedstate/api/restricted_current.txt b/savedstate/savedstate/api/restricted_current.txt
index 0f65840..f87e8a6 100644
--- a/savedstate/savedstate/api/restricted_current.txt
+++ b/savedstate/savedstate/api/restricted_current.txt
@@ -194,10 +194,8 @@
   }
 
   public final class SavedStateRegistryOwnerDelegatesKt {
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, String key, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlin.jvm.functions.Function0<? extends T> init);
-    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static inline <reified T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
+    method public static <T> kotlin.properties.ReadWriteProperty<java.lang.Object?,T> saved(androidx.savedstate.SavedStateRegistryOwner, kotlinx.serialization.KSerializer<T> serializer, optional String? key, kotlin.jvm.functions.Function0<? extends T> init);
   }
 
 }
@@ -244,6 +242,11 @@
     property public final kotlinx.serialization.descriptors.SerialDescriptor descriptor;
   }
 
+  public final class MutableStateFlowSerializerKt {
+    method public static inline <reified T> kotlinx.serialization.KSerializer<kotlinx.coroutines.flow.MutableStateFlow<T>> MutableStateFlowSerializer();
+    method public static <T> kotlinx.serialization.KSerializer<kotlinx.coroutines.flow.MutableStateFlow<T>> MutableStateFlowSerializer(kotlinx.serialization.KSerializer<T> serializer);
+  }
+
   public final class ParcelableArraySerializer implements kotlinx.serialization.KSerializer<android.os.Parcelable[]> {
     ctor public ParcelableArraySerializer();
     method public android.os.Parcelable[] deserialize(kotlinx.serialization.encoding.Decoder decoder);
diff --git a/savedstate/savedstate/bcv/native/current.txt b/savedstate/savedstate/bcv/native/current.txt
index 2f3971d..9b72797 100644
--- a/savedstate/savedstate/bcv/native/current.txt
+++ b/savedstate/savedstate/bcv/native/current.txt
@@ -161,16 +161,16 @@
 final const val androidx.savedstate/DEFAULT_LONG // androidx.savedstate/DEFAULT_LONG|{}DEFAULT_LONG[0]
     final fun <get-DEFAULT_LONG>(): kotlin/Long // androidx.savedstate/DEFAULT_LONG.<get-DEFAULT_LONG>|<get-DEFAULT_LONG>(){}[0]
 
-final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String, kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlin.String;kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlinx.serialization.KSerializer<0:0>;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final fun <#A: kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlinx.serialization/KSerializer<#A>, kotlin/String? = ..., kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlinx.serialization.KSerializer<0:0>;kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
 final fun <#A: kotlin/Any> androidx.savedstate.serialization/decodeFromSavedState(kotlinx.serialization/DeserializationStrategy<#A>, androidx.savedstate/SavedState): #A // androidx.savedstate.serialization/decodeFromSavedState|decodeFromSavedState(kotlinx.serialization.DeserializationStrategy<0:0>;androidx.savedstate.SavedState){0§<kotlin.Any>}[0]
 final fun <#A: kotlin/Any> androidx.savedstate.serialization/encodeToSavedState(kotlinx.serialization/SerializationStrategy<#A>, #A): androidx.savedstate/SavedState // androidx.savedstate.serialization/encodeToSavedState|encodeToSavedState(kotlinx.serialization.SerializationStrategy<0:0>;0:0){0§<kotlin.Any>}[0]
+final fun <#A: kotlin/Any?> androidx.savedstate.serialization.serializers/MutableStateFlowSerializer(kotlinx.serialization/KSerializer<#A>): kotlinx.serialization/KSerializer<kotlinx.coroutines.flow/MutableStateFlow<#A>> // androidx.savedstate.serialization.serializers/MutableStateFlowSerializer|MutableStateFlowSerializer(kotlinx.serialization.KSerializer<0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedState).androidx.savedstate/read(kotlin/Function1<androidx.savedstate/SavedStateReader, #A>): #A // androidx.savedstate/read|read@androidx.savedstate.SavedState(kotlin.Function1<androidx.savedstate.SavedStateReader,0:0>){0§<kotlin.Any?>}[0]
 final inline fun <#A: kotlin/Any?> (androidx.savedstate/SavedState).androidx.savedstate/write(kotlin/Function1<androidx.savedstate/SavedStateWriter, #A>): #A // androidx.savedstate/write|write@androidx.savedstate.SavedState(kotlin.Function1<androidx.savedstate.SavedStateWriter,0:0>){0§<kotlin.Any?>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String, noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlin.String;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
-final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
+final inline fun <#A: reified kotlin/Any> (androidx.savedstate/SavedStateRegistryOwner).androidx.savedstate.serialization/saved(kotlin/String? = ..., noinline kotlin/Function0<#A>): kotlin.properties/ReadWriteProperty<kotlin/Any?, #A> // androidx.savedstate.serialization/saved|saved@androidx.savedstate.SavedStateRegistryOwner(kotlin.String?;kotlin.Function0<0:0>){0§<kotlin.Any>}[0]
 final inline fun <#A: reified kotlin/Any> androidx.savedstate.serialization/decodeFromSavedState(androidx.savedstate/SavedState): #A // androidx.savedstate.serialization/decodeFromSavedState|decodeFromSavedState(androidx.savedstate.SavedState){0§<kotlin.Any>}[0]
 final inline fun <#A: reified kotlin/Any> androidx.savedstate.serialization/encodeToSavedState(#A): androidx.savedstate/SavedState // androidx.savedstate.serialization/encodeToSavedState|encodeToSavedState(0:0){0§<kotlin.Any>}[0]
+final inline fun <#A: reified kotlin/Any?> androidx.savedstate.serialization.serializers/MutableStateFlowSerializer(): kotlinx.serialization/KSerializer<kotlinx.coroutines.flow/MutableStateFlow<#A>> // androidx.savedstate.serialization.serializers/MutableStateFlowSerializer|MutableStateFlowSerializer(){0§<kotlin.Any?>}[0]
 final inline fun androidx.savedstate/keyNotFoundError(kotlin/String): kotlin/Nothing // androidx.savedstate/keyNotFoundError|keyNotFoundError(kotlin.String){}[0]
 final inline fun androidx.savedstate/savedState(kotlin.collections/Map<kotlin/String, kotlin/Any?> = ..., kotlin/Function1<androidx.savedstate/SavedStateWriter, kotlin/Unit> = ...): androidx.savedstate/SavedState // androidx.savedstate/savedState|savedState(kotlin.collections.Map<kotlin.String,kotlin.Any?>;kotlin.Function1<androidx.savedstate.SavedStateWriter,kotlin.Unit>){}[0]
 final inline fun androidx.savedstate/valueNotFoundError(kotlin/String): kotlin/Nothing // androidx.savedstate/valueNotFoundError|valueNotFoundError(kotlin.String){}[0]
diff --git a/savedstate/savedstate/build.gradle b/savedstate/savedstate/build.gradle
index b3e7304..9d326c2 100644
--- a/savedstate/savedstate/build.gradle
+++ b/savedstate/savedstate/build.gradle
@@ -32,6 +32,7 @@
                 api(libs.kotlinStdlib)
                 api("androidx.annotation:annotation:1.8.0")
                 api(projectOrArtifact(":lifecycle:lifecycle-common"))
+                api(libs.kotlinCoroutinesCore)
                 api(libs.kotlinSerializationCore)
             }
         }
diff --git a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/serialization/serializers/BuiltInSerializer.android.kt b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/serialization/serializers/BuiltInSerializer.android.kt
index 071f4c1..adb16e1 100644
--- a/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/serialization/serializers/BuiltInSerializer.android.kt
+++ b/savedstate/savedstate/src/androidMain/kotlin/androidx/savedstate/serialization/serializers/BuiltInSerializer.android.kt
@@ -117,7 +117,6 @@
         encoder.run { savedState.write { putCharSequence(key, value) } }
     }
 
-    @Suppress("UNCHECKED_CAST")
     override fun deserialize(decoder: Decoder): CharSequence {
         require(decoder is SavedStateDecoder) {
             decoderErrorMessage(descriptor.serialName, decoder)
diff --git a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
index a890db3..c11359f 100644
--- a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
+++ b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/SavedStateRegistryOwnerDelegates.kt
@@ -28,16 +28,17 @@
  * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
  *
  * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withKey_withSerializer
- * @param key The [String] key to use for storing the value in the [SavedStateRegistry].
  * @param serializer The [KSerializer] to use for serializing and deserializing the value.
+ * @param key An optional [String] key to use for storing the value in the [SavedStateRegistry]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate provider that manages the saving and restoring of the value.
  * @see encodeToSavedState
  * @see decodeFromSavedState
  */
 public fun <T : Any> SavedStateRegistryOwner.saved(
-    key: String,
     serializer: KSerializer<T>,
+    key: String? = null,
     init: () -> T,
 ): ReadWriteProperty<Any?, T> {
     return SavedStateRegistryOwnerDelegate(
@@ -52,34 +53,9 @@
  * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
  * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
  *
- * This is a convenience overload that uses the name of the property as the key for storing the
- * value in the [SavedStateRegistry]
- *
- * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withSerializer
- * @param serializer The [KSerializer] to use for serializing and deserializing the value.
- * @param init The function to provide the initial value of the property.
- * @return A property delegate provider that manages the saving and restoring of the value.
- * @see encodeToSavedState
- * @see decodeFromSavedState
- */
-public fun <T : Any> SavedStateRegistryOwner.saved(
-    serializer: KSerializer<T>,
-    init: () -> T,
-): ReadWriteProperty<Any?, T> {
-    return SavedStateRegistryOwnerDelegate(
-        registry = savedStateRegistry,
-        key = null,
-        serializer = serializer,
-        init = init
-    )
-}
-
-/**
- * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
- * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
- *
  * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved_withKey
- * @param key The [String] key to use for storing the value in the [SavedStateRegistry].
+ * @param key An optional [String] key to use for storing the value in the [SavedStateRegistry]. A
+ *   default key will be generated if it's omitted or when 'null' is passed.
  * @param init The function to provide the initial value of the property.
  * @return A property delegate provider that manages the saving and restoring of the value.
  * @see encodeToSavedState
@@ -87,30 +63,9 @@
  * @see serializer
  */
 public inline fun <reified T : Any> SavedStateRegistryOwner.saved(
-    key: String,
+    key: String? = null,
     noinline init: () -> T,
-): ReadWriteProperty<Any?, T> = saved(key = key, serializer = serializer(), init = init)
-
-/**
- * Returns a property delegate provider that manages the saving and restoring of a value of type [T]
- * within the [SavedStateRegistry] of this [SavedStateRegistryOwner].
- *
- * This is a convenience overload that uses the [serializer] function to obtain the serializer for
- * the reified type [T].
- *
- * The name of the property will be used as the key for storing the value in the
- * [SavedStateRegistry].
- *
- * @sample androidx.savedstate.serialization.savedStateRegistryOwner_saved
- * @param init The function to provide the initial value of the property.
- * @return A property delegate provider that manages the saving and restoring of the value.
- * @see encodeToSavedState
- * @see decodeFromSavedState
- * @see serializer
- */
-public inline fun <reified T : Any> SavedStateRegistryOwner.saved(
-    noinline init: () -> T,
-): ReadWriteProperty<Any?, T> = saved(serializer = serializer(), init = init)
+): ReadWriteProperty<Any?, T> = saved(serializer = serializer(), key = key, init = init)
 
 private class SavedStateRegistryOwnerDelegate<T : Any>(
     private val registry: SavedStateRegistry,
diff --git a/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/serializers/MutableStateFlowSerializer.kt b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/serializers/MutableStateFlowSerializer.kt
new file mode 100644
index 0000000..eb076e05
--- /dev/null
+++ b/savedstate/savedstate/src/commonMain/kotlin/androidx/savedstate/serialization/serializers/MutableStateFlowSerializer.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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:OptIn(InternalSerializationApi::class, ExperimentalTypeInference::class)
+
+package androidx.savedstate.serialization.serializers
+
+import kotlin.experimental.ExperimentalTypeInference
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.serializer
+
+/**
+ * Creates a [KSerializer] for a [MutableStateFlow] containing a [Serializable] value of type [T].
+ *
+ * This inline function infers the state type [T] automatically and retrieves the appropriate
+ * [KSerializer] for serialization and deserialization of [MutableStateFlow].
+ *
+ * @param T The type of the value stored in the [MutableStateFlow].
+ * @return A [KSerializer] for handling [MutableStateFlow] containing a [Serializable] type [T].
+ */
+public inline fun <reified T> MutableStateFlowSerializer(): KSerializer<MutableStateFlow<T>> {
+    return MutableStateFlowSerializer(serializer())
+}
+
+/**
+ * Creates a [KSerializer] for a [MutableStateFlow] containing a [Serializable] value of type [T].
+ *
+ * This function allows for explicit specification of the [KSerializer] for the state type [T]. It
+ * provides serialization and deserialization capabilities for [MutableStateFlow] objects.
+ *
+ * @param T The type of the value stored in the [MutableStateFlow].
+ * @param serializer The [KSerializer] for the [Serializable] type [T].
+ * @return A [KSerializer] for handling [MutableStateFlow] containing a [Serializable] type [T].
+ */
+public fun <T> MutableStateFlowSerializer(
+    serializer: KSerializer<T>
+): KSerializer<MutableStateFlow<T>> {
+    return MutableStateFlowSerializerImpl<T>(serializer)
+}
+
+/**
+ * Internal implementation of [KSerializer] for [MutableStateFlow].
+ *
+ * This private class wraps a [KSerializer] for the inner value type [T], enabling serialization and
+ * deserialization of [MutableStateFlow] instances. The inner value serialization is delegated to
+ * the provided [valueSerializer].
+ *
+ * @param T The type of the value stored in the [MutableStateFlow].
+ * @property valueSerializer The [KSerializer] used to serialize and deserialize the inner value.
+ */
+private class MutableStateFlowSerializerImpl<T>(
+    private val valueSerializer: KSerializer<T>,
+) : KSerializer<MutableStateFlow<T>> {
+
+    override val descriptor: SerialDescriptor = valueSerializer.descriptor
+
+    override fun serialize(encoder: Encoder, value: MutableStateFlow<T>) {
+        valueSerializer.serialize(encoder, value.value)
+    }
+
+    override fun deserialize(decoder: Decoder): MutableStateFlow<T> {
+        return MutableStateFlow(valueSerializer.deserialize(decoder))
+    }
+}
diff --git a/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/serialization/MutableStateFlowSerializerTest.kt b/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/serialization/MutableStateFlowSerializerTest.kt
new file mode 100644
index 0000000..1c38889
--- /dev/null
+++ b/savedstate/savedstate/src/commonTest/kotlin/androidx/savedstate/serialization/MutableStateFlowSerializerTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.savedstate.serialization
+
+import androidx.kruth.assertThat
+import androidx.savedstate.RobolectricTest
+import androidx.savedstate.serialization.serializers.MutableStateFlowSerializer
+import kotlin.test.Test
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.serializer
+
+internal class MutableStateFlowSerializerTest : RobolectricTest() {
+
+    @Test
+    fun encodeDecode_withImplicitSerializer() {
+        val state = MutableStateFlow(USER_JOHN_DOE)
+        val serializer = MutableStateFlowSerializer<User>()
+
+        val encoded = encodeToSavedState(serializer, state)
+        val decoded = decodeFromSavedState(serializer, encoded)
+
+        assertThat(state.value).isEqualTo(decoded.value)
+    }
+
+    @Test
+    fun encodeDecode_withExplicitSerializer() {
+        val state = MutableStateFlow(USER_JOHN_DOE)
+        val serializer = MutableStateFlowSerializer(USER_SERIALIZER)
+
+        val encoded = encodeToSavedState(serializer, state)
+        val decoded = decodeFromSavedState(serializer, encoded)
+
+        assertThat(state.value).isEqualTo(decoded.value)
+    }
+
+    companion object {
+        val USER_JOHN_DOE = User(name = "John", surname = "Doe")
+        @OptIn(InternalSerializationApi::class) val USER_SERIALIZER = User::class.serializer()
+    }
+
+    @Serializable data class User(val name: String = "John", val surname: String = "Doe")
+}
diff --git a/security/security-state-provider/src/main/java/androidx/security/state/provider/UpdateInfoManager.kt b/security/security-state-provider/src/main/java/androidx/security/state/provider/UpdateInfoManager.kt
index f04ac2ff..b0e695b 100644
--- a/security/security-state-provider/src/main/java/androidx/security/state/provider/UpdateInfoManager.kt
+++ b/security/security-state-provider/src/main/java/androidx/security/state/provider/UpdateInfoManager.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import androidx.security.state.SecurityPatchState
+import androidx.security.state.SecurityPatchState.Companion.getComponentSecurityPatchLevel
 import kotlinx.serialization.json.Json
 
 /**
@@ -93,11 +94,7 @@
                 // Ignore unknown components.
                 return@forEach
             }
-            val updateSpl =
-                securityState.getComponentSecurityPatchLevel(
-                    component,
-                    updateInfo.securityPatchLevel
-                )
+            val updateSpl = getComponentSecurityPatchLevel(component, updateInfo.securityPatchLevel)
 
             if (updateSpl <= currentSpl) {
                 val key = getKeyForUpdateInfo(updateInfo)
diff --git a/security/security-state-provider/src/test/java/androidx/security/state/provider/UpdateInfoManagerTest.kt b/security/security-state-provider/src/test/java/androidx/security/state/provider/UpdateInfoManagerTest.kt
index 81b6111..a87a5d7 100644
--- a/security/security-state-provider/src/test/java/androidx/security/state/provider/UpdateInfoManagerTest.kt
+++ b/security/security-state-provider/src/test/java/androidx/security/state/provider/UpdateInfoManagerTest.kt
@@ -33,20 +33,13 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.`when`
 import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 
 @RunWith(AndroidJUnit4::class)
 class UpdateInfoManagerTest {
 
     private lateinit var manager: UpdateInfoManager
-    private val mockSpl = SecurityPatchState.DateBasedSecurityPatchLevel(2022, 1, 1)
-    private val mockSecurityState: SecurityPatchState =
-        mock<SecurityPatchState> {
-            on {
-                getComponentSecurityPatchLevel(eq(COMPONENT_SYSTEM), Mockito.anyString())
-            } doReturn mockSpl
-        }
+    private val mockSecurityState: SecurityPatchState = mock<SecurityPatchState>()
     @SuppressLint("NewApi")
     private val publishedDate = Date.from(LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC))
     private val updateInfo =
diff --git a/security/security-state/api/current.txt b/security/security-state/api/current.txt
index 510499b..8cae039 100644
--- a/security/security-state/api/current.txt
+++ b/security/security-state/api/current.txt
@@ -3,16 +3,17 @@
 
   public class SecurityPatchState {
     ctor public SecurityPatchState(android.content.Context context);
-    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModules);
-    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModules, optional androidx.security.state.SecurityStateManager? customSecurityStateManager);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames, optional androidx.security.state.SecurityStateManagerCompat? customSecurityStateManagerCompat);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames, optional androidx.security.state.SecurityStateManagerCompat? customSecurityStateManagerCompat, optional String? vulnerabilityReportJsonString);
     method public final boolean areCvesPatched(java.util.List<java.lang.String> cveList);
-    method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
+    method public static final androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
     method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getDeviceSecurityPatchLevel(String component);
     method public java.util.Map<androidx.security.state.SecurityPatchState.Severity,java.util.Set<java.lang.String>> getPatchedCves(String component, androidx.security.state.SecurityPatchState.SecurityPatchLevel spl);
     method public java.util.List<androidx.security.state.SecurityPatchState.SecurityPatchLevel> getPublishedSecurityPatchLevel(String component);
-    method @RequiresApi(26) public final android.net.Uri getVulnerabilityReportUrl(android.net.Uri serverUrl);
+    method @RequiresApi(26) public static final android.net.Uri getVulnerabilityReportUrl(optional android.net.Uri serverUrl);
     method public final boolean isDeviceFullyUpdated();
-    method public final void loadVulnerabilityReport(String jsonString);
+    method @WorkerThread public final void loadVulnerabilityReport(String jsonString);
     field public static final String COMPONENT_KERNEL = "KERNEL";
     field public static final String COMPONENT_SYSTEM = "SYSTEM";
     field public static final String COMPONENT_SYSTEM_MODULES = "SYSTEM_MODULES";
@@ -22,6 +23,8 @@
   }
 
   public static final class SecurityPatchState.Companion {
+    method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
+    method @RequiresApi(26) public android.net.Uri getVulnerabilityReportUrl(optional android.net.Uri serverUrl);
     property public static final String COMPONENT_KERNEL;
     property public static final String COMPONENT_SYSTEM;
     property public static final String COMPONENT_SYSTEM_MODULES;
@@ -75,16 +78,16 @@
     method public androidx.security.state.SecurityPatchState.VersionedSecurityPatchLevel fromString(String value);
   }
 
-  public class SecurityStateManager {
-    ctor public SecurityStateManager(android.content.Context context);
-    method public android.os.Bundle getGlobalSecurityState(optional String? moduleMetadataProvider);
-    field public static final androidx.security.state.SecurityStateManager.Companion Companion;
+  public class SecurityStateManagerCompat {
+    ctor public SecurityStateManagerCompat(android.content.Context context);
+    method public android.os.Bundle getGlobalSecurityState(optional String moduleMetadataProviderPackageName);
+    field public static final androidx.security.state.SecurityStateManagerCompat.Companion Companion;
     field public static final String KEY_KERNEL_VERSION = "kernel_version";
     field public static final String KEY_SYSTEM_SPL = "system_spl";
     field public static final String KEY_VENDOR_SPL = "vendor_spl";
   }
 
-  public static final class SecurityStateManager.Companion {
+  public static final class SecurityStateManagerCompat.Companion {
     property public static final String KEY_KERNEL_VERSION;
     property public static final String KEY_SYSTEM_SPL;
     property public static final String KEY_VENDOR_SPL;
diff --git a/security/security-state/api/restricted_current.txt b/security/security-state/api/restricted_current.txt
index 510499b..8cae039 100644
--- a/security/security-state/api/restricted_current.txt
+++ b/security/security-state/api/restricted_current.txt
@@ -3,16 +3,17 @@
 
   public class SecurityPatchState {
     ctor public SecurityPatchState(android.content.Context context);
-    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModules);
-    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModules, optional androidx.security.state.SecurityStateManager? customSecurityStateManager);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames, optional androidx.security.state.SecurityStateManagerCompat? customSecurityStateManagerCompat);
+    ctor public SecurityPatchState(android.content.Context context, optional java.util.List<java.lang.String> systemModulePackageNames, optional androidx.security.state.SecurityStateManagerCompat? customSecurityStateManagerCompat, optional String? vulnerabilityReportJsonString);
     method public final boolean areCvesPatched(java.util.List<java.lang.String> cveList);
-    method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
+    method public static final androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
     method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getDeviceSecurityPatchLevel(String component);
     method public java.util.Map<androidx.security.state.SecurityPatchState.Severity,java.util.Set<java.lang.String>> getPatchedCves(String component, androidx.security.state.SecurityPatchState.SecurityPatchLevel spl);
     method public java.util.List<androidx.security.state.SecurityPatchState.SecurityPatchLevel> getPublishedSecurityPatchLevel(String component);
-    method @RequiresApi(26) public final android.net.Uri getVulnerabilityReportUrl(android.net.Uri serverUrl);
+    method @RequiresApi(26) public static final android.net.Uri getVulnerabilityReportUrl(optional android.net.Uri serverUrl);
     method public final boolean isDeviceFullyUpdated();
-    method public final void loadVulnerabilityReport(String jsonString);
+    method @WorkerThread public final void loadVulnerabilityReport(String jsonString);
     field public static final String COMPONENT_KERNEL = "KERNEL";
     field public static final String COMPONENT_SYSTEM = "SYSTEM";
     field public static final String COMPONENT_SYSTEM_MODULES = "SYSTEM_MODULES";
@@ -22,6 +23,8 @@
   }
 
   public static final class SecurityPatchState.Companion {
+    method public androidx.security.state.SecurityPatchState.SecurityPatchLevel getComponentSecurityPatchLevel(String component, String securityPatchLevel);
+    method @RequiresApi(26) public android.net.Uri getVulnerabilityReportUrl(optional android.net.Uri serverUrl);
     property public static final String COMPONENT_KERNEL;
     property public static final String COMPONENT_SYSTEM;
     property public static final String COMPONENT_SYSTEM_MODULES;
@@ -75,16 +78,16 @@
     method public androidx.security.state.SecurityPatchState.VersionedSecurityPatchLevel fromString(String value);
   }
 
-  public class SecurityStateManager {
-    ctor public SecurityStateManager(android.content.Context context);
-    method public android.os.Bundle getGlobalSecurityState(optional String? moduleMetadataProvider);
-    field public static final androidx.security.state.SecurityStateManager.Companion Companion;
+  public class SecurityStateManagerCompat {
+    ctor public SecurityStateManagerCompat(android.content.Context context);
+    method public android.os.Bundle getGlobalSecurityState(optional String moduleMetadataProviderPackageName);
+    field public static final androidx.security.state.SecurityStateManagerCompat.Companion Companion;
     field public static final String KEY_KERNEL_VERSION = "kernel_version";
     field public static final String KEY_SYSTEM_SPL = "system_spl";
     field public static final String KEY_VENDOR_SPL = "vendor_spl";
   }
 
-  public static final class SecurityStateManager.Companion {
+  public static final class SecurityStateManagerCompat.Companion {
     property public static final String KEY_KERNEL_VERSION;
     property public static final String KEY_SYSTEM_SPL;
     property public static final String KEY_VENDOR_SPL;
diff --git a/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt b/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerCompatTest.kt
similarity index 88%
rename from security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt
rename to security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerCompatTest.kt
index 7d2ddfa..3c72447 100644
--- a/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerTest.kt
+++ b/security/security-state/src/androidTest/java/androidx/security/state/SecurityStateManagerCompatTest.kt
@@ -32,14 +32,14 @@
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
-class SecurityStateManagerTest {
+class SecurityStateManagerCompatTest {
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
-    private lateinit var securityStateManager: SecurityStateManager
+    private lateinit var securityStateManagerCompat: SecurityStateManagerCompat
 
     @Before
     fun setup() {
-        securityStateManager = SecurityStateManager(context)
+        securityStateManagerCompat = SecurityStateManagerCompat(context)
     }
 
     /** Returns `true` if [date] is in the format "YYYY-MM-DD". */
@@ -85,7 +85,7 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     @Test
     fun testGetGlobalSecurityState_sdkAbove29() {
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertTrue(containsModuleMetadataPackage(bundle))
@@ -95,7 +95,7 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O, maxSdkVersion = Build.VERSION_CODES.P)
     @Test
     fun testGetGlobalSecurityState_sdkAbove25Below29_doesNotContainModuleMetadata() {
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertTrue(containsWebViewPackage(bundle))
@@ -105,7 +105,7 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.M, maxSdkVersion = Build.VERSION_CODES.N_MR1)
     @Test
     fun testGetGlobalSecurityState_sdkAbove22Below26_doesNotContainModuleMetadataOrWebView() {
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertTrue(matchesDateFormat(bundle.getString("system_spl")!!))
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertFalse(containsModuleMetadataPackage(bundle))
@@ -118,7 +118,7 @@
     )
     @Test
     fun testGetGlobalSecurityState_sdkBelow23_containsOnlyKernel() {
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertTrue(matchesKernelFormat(bundle.getString("kernel_version")!!))
         assertFalse(bundle.containsKey("system_spl"))
         assertFalse(bundle.containsKey("vendor_spl"))
@@ -130,7 +130,7 @@
     @Test
     fun testGetGlobalSecurityState_whenVendorIsEnabled_containsVendorSpl() {
         SecurityPatchState.Companion.USE_VENDOR_SPL = true
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertTrue(bundle.containsKey("vendor_spl"))
     }
 
@@ -138,7 +138,7 @@
     @Test
     fun testGetGlobalSecurityState_whenVendorIsDisabled_doesNotContainVendorSpl() {
         SecurityPatchState.Companion.USE_VENDOR_SPL = false
-        val bundle = securityStateManager.getGlobalSecurityState()
+        val bundle = securityStateManagerCompat.getGlobalSecurityState()
         assertFalse(bundle.containsKey("vendor_spl"))
     }
 
@@ -149,7 +149,7 @@
             return // Skip this test on non-Google devices.
         }
         val bundle =
-            securityStateManager.getGlobalSecurityState("com.google.android.modulemetadata")
+            securityStateManagerCompat.getGlobalSecurityState("com.google.android.modulemetadata")
         DateBasedSecurityPatchLevel.fromString(
             bundle.getString("com.google.android.modulemetadata")!!
         )
diff --git a/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt b/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
index 455fe21..bcc3f13 100644
--- a/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
+++ b/security/security-state/src/main/java/androidx/security/state/SecurityPatchState.kt
@@ -19,11 +19,13 @@
 import android.annotation.SuppressLint
 import android.content.Context
 import android.net.Uri
+import android.os.Build
 import androidx.annotation.RequiresApi
 import androidx.annotation.StringDef
-import androidx.security.state.SecurityStateManager.Companion.KEY_KERNEL_VERSION
-import androidx.security.state.SecurityStateManager.Companion.KEY_SYSTEM_SPL
-import androidx.security.state.SecurityStateManager.Companion.KEY_VENDOR_SPL
+import androidx.annotation.WorkerThread
+import androidx.security.state.SecurityStateManagerCompat.Companion.KEY_KERNEL_VERSION
+import androidx.security.state.SecurityStateManagerCompat.Companion.KEY_SYSTEM_SPL
+import androidx.security.state.SecurityStateManagerCompat.Companion.KEY_VENDOR_SPL
 import java.text.ParseException
 import java.text.SimpleDateFormat
 import java.util.Calendar
@@ -48,27 +50,48 @@
  * The class uses a combination of local data storage and external data fetching to maintain and
  * update security states.
  *
+ * Recommended pattern of usage:
+ * - call [getVulnerabilityReportUrl] and make a request to download the JSON file containing
+ *   vulnerability report data
+ * - create SecurityPatchState object, passing in the downloaded JSON as a [String]
+ * - call [getPublishedSecurityPatchLevel] or other APIs
+ *
  * @param context Application context used for accessing shared preferences, resources, and other
  *   context-dependent features.
- * @param systemModules A list of system module package names, defaults to Google provided system
- *   modules if none are provided. The first module on the list must be the system modules metadata
- *   provider package.
- * @param customSecurityStateManager An optional custom manager for obtaining security state
+ * @param systemModulePackageNames A list of system module package names, defaults to Google
+ *   provided system modules if none are provided. The first module on the list must be the system
+ *   modules metadata provider package.
+ * @param customSecurityStateManagerCompat An optional custom manager for obtaining security state
  *   information. If null, a default manager is instantiated.
+ * @param vulnerabilityReportJsonString A JSON string containing vulnerability data to initialize a
+ *   [VulnerabilityReport] object.
+ *
+ *   If you only care about the Device SPL, this parameter is optional. If you need access to
+ *   Published SPL and Available SPL, you must provide this JSON string, either here in the
+ *   constructor, or later using [loadVulnerabilityReport].
+ *
  * @constructor Creates an instance of SecurityPatchState.
  */
 public open class SecurityPatchState
 @JvmOverloads
 constructor(
     private val context: Context,
-    private val systemModules: List<String> = listOf(),
-    private val customSecurityStateManager: SecurityStateManager? = null
+    private val systemModulePackageNames: List<String> = DEFAULT_SYSTEM_MODULES,
+    private val customSecurityStateManagerCompat: SecurityStateManagerCompat? = null,
+    vulnerabilityReportJsonString: String? = null
 ) {
-    private val securityStateManager =
-        customSecurityStateManager ?: SecurityStateManager(context = context)
+    init {
+        if (vulnerabilityReportJsonString != null) {
+            loadVulnerabilityReport(vulnerabilityReportJsonString)
+        }
+    }
+
+    private val securityStateManagerCompat =
+        customSecurityStateManagerCompat ?: SecurityStateManagerCompat(context = context)
     private var vulnerabilityReport: VulnerabilityReport? = null
 
     public companion object {
+        /** Default list of Android Mainline system modules. */
         @JvmField
         public val DEFAULT_SYSTEM_MODULES: List<String> =
             listOf(
@@ -102,6 +125,63 @@
 
         /** Disabled until Android provides sufficient guidelines for the usage of Vendor SPL. */
         internal var USE_VENDOR_SPL = false
+
+        /**
+         * Retrieves the specific security patch level for a given component based on a security
+         * patch level string. This method determines the type of [SecurityPatchLevel] to construct
+         * based on the component type, interpreting the string as a date for date-based components
+         * or as a version number for versioned components.
+         *
+         * @param component The component indicating which type of component's patch level is being
+         *   requested.
+         * @param securityPatchLevel The string representation of the security patch level, which
+         *   could be a date or a version number.
+         * @return A [SecurityPatchLevel] instance corresponding to the specified component and
+         *   patch level string.
+         * @throws IllegalArgumentException If the input string is not in a valid format for the
+         *   specified component type, or if the component requires a specific format that the
+         *   string does not meet.
+         */
+        @JvmStatic
+        public fun getComponentSecurityPatchLevel(
+            @Component component: String,
+            securityPatchLevel: String
+        ): SecurityPatchLevel {
+            val exception = IllegalArgumentException("Unknown component: $component")
+            return when (component) {
+                COMPONENT_SYSTEM,
+                COMPONENT_SYSTEM_MODULES,
+                COMPONENT_VENDOR -> {
+                    if (component == COMPONENT_VENDOR && !USE_VENDOR_SPL) {
+                        throw exception
+                    }
+                    // These components are expected to use DateBasedSpl
+                    DateBasedSecurityPatchLevel.fromString(securityPatchLevel)
+                }
+                COMPONENT_KERNEL -> {
+                    // These components are expected to use VersionedSpl
+                    VersionedSecurityPatchLevel.fromString(securityPatchLevel)
+                }
+                else -> throw exception
+            }
+        }
+
+        /**
+         * Constructs a URL for fetching vulnerability reports based on the device's Android
+         * version.
+         *
+         * @param serverUrl The base URL of the server where vulnerability reports are stored.
+         * @return A fully constructed URL pointing to the specific vulnerability report for this
+         *   device.
+         */
+        @JvmStatic
+        @RequiresApi(26)
+        public fun getVulnerabilityReportUrl(
+            serverUrl: Uri = Uri.parse(DEFAULT_VULNERABILITY_REPORTS_URL)
+        ): Uri {
+            val newEndpoint = "v1/android_sdk_${Build.VERSION.SDK_INT}.json"
+            return serverUrl.buildUpon().appendEncodedPath(newEndpoint).build()
+        }
     }
 
     /** Annotation for defining the component to use. */
@@ -162,6 +242,13 @@
         public companion object {
             private val DATE_FORMATS = listOf("yyyy-MM", "yyyy-MM-dd")
 
+            /**
+             * Creates a new [DateBasedSecurityPatchLevel] from a string representation of the date.
+             *
+             * @param value The date string in the format of [DATE_FORMATS].
+             * @return A new [DateBasedSecurityPatchLevel] representing the date.
+             * @throws IllegalArgumentException if the date string is not in the correct format.
+             */
             @JvmStatic
             public fun fromString(value: String): DateBasedSecurityPatchLevel {
                 var date: Date? = null
@@ -227,6 +314,14 @@
     ) : SecurityPatchLevel() {
 
         public companion object {
+            /**
+             * Creates a new [VersionedSecurityPatchLevel] from a string representation of the
+             * version.
+             *
+             * @param value The version string in the format of "major.minor.build.patch".
+             * @return A new [VersionedSecurityPatchLevel] representing the version.
+             * @throws IllegalArgumentException if the version string is not in the correct format.
+             */
             @JvmStatic
             public fun fromString(value: String): VersionedSecurityPatchLevel {
                 val parts = value.split(".")
@@ -329,8 +424,7 @@
      * @return A list of strings representing system module identifiers.
      */
     internal fun getSystemModules(): List<String> {
-        // Use the provided systemModules if not empty; otherwise, use defaultSystemModules
-        return systemModules.ifEmpty { DEFAULT_SYSTEM_MODULES }
+        return systemModulePackageNames.ifEmpty { DEFAULT_SYSTEM_MODULES }
     }
 
     /**
@@ -338,16 +432,10 @@
      * of the input JSON and constructs a [VulnerabilityReport] object, preparing the class to
      * provide published and available security state information.
      *
-     * The recommended pattern of usage:
-     * - create SecurityPatchState object
-     * - call getVulnerabilityReportUrl()
-     * - download JSON file containing vulnerability report data
-     * - call loadVulnerabilityReport()
-     * - call getPublishedSecurityPatchLevel() or other APIs
-     *
      * @param jsonString The JSON string containing the vulnerability data.
      * @throws IllegalArgumentException if the JSON input is malformed or contains invalid data.
      */
+    @WorkerThread
     public fun loadVulnerabilityReport(jsonString: String) {
         val result: VulnerabilityReport
 
@@ -426,27 +514,6 @@
         vulnerabilityReport = result
     }
 
-    /**
-     * Constructs a URL for fetching vulnerability reports based on the device's Android version.
-     *
-     * @param serverUrl The base URL of the server where vulnerability reports are stored.
-     * @return A fully constructed URL pointing to the specific vulnerability report for this
-     *   device.
-     * @throws IllegalArgumentException if the Android SDK version is unsupported.
-     */
-    @RequiresApi(26)
-    public fun getVulnerabilityReportUrl(serverUrl: Uri): Uri {
-        val androidSdk = securityStateManager.getAndroidSdkInt()
-        if (androidSdk < 26) {
-            throw IllegalArgumentException(
-                "Unsupported SDK version (must be > 25), found $androidSdk."
-            )
-        }
-
-        val newEndpoint = "v1/android_sdk_$androidSdk.json"
-        return serverUrl.buildUpon().appendEncodedPath(newEndpoint).build()
-    }
-
     private fun getMaxComponentSecurityPatchLevel(
         @Component component: String
     ): DateBasedSecurityPatchLevel? {
@@ -488,7 +555,7 @@
             try {
                 packageSpl =
                     DateBasedSecurityPatchLevel.fromString(
-                        securityStateManager.getPackageVersion(module)
+                        securityStateManagerCompat.getPackageVersion(module)
                     )
             } catch (e: Exception) {
                 // Prevent malformed package versions from interrupting the loop.
@@ -541,7 +608,8 @@
      * @throws IllegalArgumentException if the component name is unrecognized.
      */
     public open fun getDeviceSecurityPatchLevel(@Component component: String): SecurityPatchLevel {
-        val globalSecurityState = securityStateManager.getGlobalSecurityState(getSystemModules()[0])
+        val globalSecurityState =
+            securityStateManagerCompat.getGlobalSecurityState(getSystemModules()[0])
 
         return when (component) {
             COMPONENT_SYSTEM_MODULES -> {
@@ -700,45 +768,6 @@
     }
 
     /**
-     * Retrieves the specific security patch level for a given component based on a security patch
-     * level string. This method determines the type of [SecurityPatchLevel] to construct based on
-     * the component type, interpreting the string as a date for date-based components or as a
-     * version number for versioned components.
-     *
-     * @param component The component indicating which type of component's patch level is being
-     *   requested.
-     * @param securityPatchLevel The string representation of the security patch level, which could
-     *   be a date or a version number.
-     * @return A [SecurityPatchLevel] instance corresponding to the specified component and patch
-     *   level string.
-     * @throws IllegalArgumentException If the input string is not in a valid format for the
-     *   specified component type, or if the component requires a specific format that the string
-     *   does not meet.
-     */
-    public open fun getComponentSecurityPatchLevel(
-        @Component component: String,
-        securityPatchLevel: String
-    ): SecurityPatchLevel {
-        val exception = IllegalArgumentException("Unknown component: $component")
-        return when (component) {
-            COMPONENT_SYSTEM,
-            COMPONENT_SYSTEM_MODULES,
-            COMPONENT_VENDOR -> {
-                if (component == COMPONENT_VENDOR && !USE_VENDOR_SPL) {
-                    throw exception
-                }
-                // These components are expected to use DateBasedSpl
-                DateBasedSecurityPatchLevel.fromString(securityPatchLevel)
-            }
-            COMPONENT_KERNEL -> {
-                // These components are expected to use VersionedSpl
-                VersionedSecurityPatchLevel.fromString(securityPatchLevel)
-            }
-            else -> throw exception
-        }
-    }
-
-    /**
      * Checks if all components of the device have their security patch levels up to date with the
      * published security patch levels. This method compares the device's current security patch
      * level against the latest published levels for each component.
diff --git a/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt b/security/security-state/src/main/java/androidx/security/state/SecurityStateManagerCompat.kt
similarity index 88%
rename from security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt
rename to security/security-state/src/main/java/androidx/security/state/SecurityStateManagerCompat.kt
index 2676d6c..d5abdca 100644
--- a/security/security-state/src/main/java/androidx/security/state/SecurityStateManager.kt
+++ b/security/security-state/src/main/java/androidx/security/state/SecurityStateManagerCompat.kt
@@ -40,7 +40,7 @@
  * security-related information, which is crucial for maintaining the security integrity of the
  * device.
  */
-public open class SecurityStateManager(private val context: Context) {
+public open class SecurityStateManagerCompat(private val context: Context) {
 
     public companion object {
         private const val TAG = "SecurityStateManager"
@@ -76,26 +76,24 @@
      * and module information into a Bundle. This method can optionally use Google's module metadata
      * providers to enhance the data returned.
      *
-     * @param moduleMetadataProvider Specifies package name for system modules metadata.
+     * @param moduleMetadataProviderPackageName Specifies package name for system modules metadata.
      * @return A Bundle containing keys and values representing the security state of the system,
      *   vendor, and kernel.
      */
-    @SuppressLint("NewApi") // Lint does not detect version check below.
-    public open fun getGlobalSecurityState(moduleMetadataProvider: String? = null): Bundle {
-        if (getAndroidSdkInt() >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+    public open fun getGlobalSecurityState(
+        moduleMetadataProviderPackageName: String = ANDROID_MODULE_METADATA_PROVIDER
+    ): Bundle {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
             return getGlobalSecurityStateFromService()
         }
         return Bundle().apply {
-            if (getAndroidSdkInt() >= Build.VERSION_CODES.M) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 putString(KEY_SYSTEM_SPL, Build.VERSION.SECURITY_PATCH)
                 if (USE_VENDOR_SPL) {
                     putString(KEY_VENDOR_SPL, getVendorSpl())
                 }
             }
-            if (getAndroidSdkInt() >= Build.VERSION_CODES.Q) {
-                val moduleMetadataProviderPackageName =
-                    moduleMetadataProvider ?: ANDROID_MODULE_METADATA_PROVIDER
-
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                 if (moduleMetadataProviderPackageName.isNotEmpty()) {
                     putString(
                         moduleMetadataProviderPackageName,
@@ -107,7 +105,9 @@
             if (kernelVersion.isNotEmpty()) {
                 putString(KEY_KERNEL_VERSION, kernelVersion)
             }
-            addWebViewPackages(this)
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                addWebViewPackages(this)
+            }
         }
     }
 
@@ -159,9 +159,6 @@
      */
     @RequiresApi(26)
     private fun addWebViewPackages(bundle: Bundle) {
-        if (getAndroidSdkInt() < Build.VERSION_CODES.O) {
-            return
-        }
         val packageName = getCurrentWebViewPackageName()
         if (packageName.isNotEmpty()) {
             bundle.putString(packageName, getPackageVersion(packageName))
@@ -187,15 +184,6 @@
     }
 
     /**
-     * Retrieves the SDK version of the current Android system.
-     *
-     * @return the SDK version as an integer.
-     */
-    internal open fun getAndroidSdkInt(): Int {
-        return Build.VERSION.SDK_INT
-    }
-
-    /**
      * Safely retrieves the current security patch level of the device's operating system. This
      * method ensures compatibility by checking the Android version before attempting to access APIs
      * that are not available on older versions.
@@ -203,9 +191,8 @@
      * @return A string representing the current security patch level, or empty string if it cannot
      *   be retrieved.
      */
-    @SuppressLint("NewApi") // Lint does not detect version check below.
     internal fun getSecurityPatchLevelSafe(): String {
-        return if (getAndroidSdkInt() >= Build.VERSION_CODES.M) {
+        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             Build.VERSION.SECURITY_PATCH
         } else {
             ""
diff --git a/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt b/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
index 440fd0f6..a09f5b7 100644
--- a/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
+++ b/security/security-state/src/test/java/androidx/security/state/SecurityPatchStateTest.kt
@@ -21,6 +21,7 @@
 import android.os.Build
 import android.os.Bundle
 import androidx.annotation.RequiresApi
+import androidx.security.state.SecurityPatchState.Companion.getComponentSecurityPatchLevel
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
@@ -39,12 +40,13 @@
 class SecurityPatchStateTest {
 
     private val mockContext: Context = mock<Context>()
-    private val mockSecurityStateManager: SecurityStateManager = mock<SecurityStateManager> {}
+    private val mockSecurityStateManagerCompat: SecurityStateManagerCompat =
+        mock<SecurityStateManagerCompat> {}
     private lateinit var securityState: SecurityPatchState
 
     @Before
     fun setup() {
-        securityState = SecurityPatchState(mockContext, listOf(), mockSecurityStateManager)
+        securityState = SecurityPatchState(mockContext, listOf(), mockSecurityStateManagerCompat)
     }
 
     @Test
@@ -54,11 +56,7 @@
 
     @Test
     fun testGetComponentSecurityPatchLevel_withSystemComponent_returnsDateBasedSpl() {
-        val spl =
-            securityState.getComponentSecurityPatchLevel(
-                SecurityPatchState.COMPONENT_SYSTEM,
-                "2022-01-01"
-            )
+        val spl = getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM, "2022-01-01")
         assertTrue(spl is SecurityPatchState.DateBasedSecurityPatchLevel)
         assertEquals("2022-01-01", spl.toString())
     }
@@ -66,11 +64,7 @@
     @Test
     fun testGetComponentSecurityPatchLevel_withVendorComponent_whenVendorIsEnabled_returnsDateBasedSpl() {
         SecurityPatchState.Companion.USE_VENDOR_SPL = true
-        val spl =
-            securityState.getComponentSecurityPatchLevel(
-                SecurityPatchState.COMPONENT_VENDOR,
-                "2022-01-01"
-            )
+        val spl = getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_VENDOR, "2022-01-01")
         assertTrue(spl is SecurityPatchState.DateBasedSecurityPatchLevel)
         assertEquals("2022-01-01", spl.toString())
     }
@@ -79,48 +73,28 @@
     fun testGetComponentSecurityPatchLevel_withVendorComponent_whenVendorIsDisabled_throwsException() {
         SecurityPatchState.Companion.USE_VENDOR_SPL = false
 
-        securityState.getComponentSecurityPatchLevel(
-            SecurityPatchState.COMPONENT_VENDOR,
-            "2022-01-01"
-        )
+        getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_VENDOR, "2022-01-01")
     }
 
     @Test
     fun testGetComponentSecurityPatchLevel_withKernelComponent_returnsVersionedSpl() {
-        val spl =
-            securityState.getComponentSecurityPatchLevel(
-                SecurityPatchState.COMPONENT_KERNEL,
-                "1.2.3.4"
-            )
+        val spl = getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL, "1.2.3.4")
         assertTrue(spl is SecurityPatchState.VersionedSecurityPatchLevel)
         assertEquals("1.2.3.4", spl.toString())
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testGetComponentSecurityPatchLevel_withInvalidDateBasedInput_throwsException() {
-        securityState.getComponentSecurityPatchLevel(
-            SecurityPatchState.COMPONENT_SYSTEM,
-            "invalid-date"
-        )
+        getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM, "invalid-date")
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun testGetComponentSecurityPatchLevel_withInvalidVersionedInput_throwsException() {
-        securityState.getComponentSecurityPatchLevel(
-            SecurityPatchState.COMPONENT_KERNEL,
-            "invalid-version"
-        )
-    }
-
-    @RequiresApi(Build.VERSION_CODES.O)
-    @Config(maxSdk = Build.VERSION_CODES.N_MR1)
-    @Test(expected = IllegalArgumentException::class)
-    fun testGetVulnerabilityReportUrl_withUnsupportedSdk_throwsException() {
-        securityState.getVulnerabilityReportUrl(Uri.parse("https://example.com"))
+        getComponentSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL, "invalid-version")
     }
 
     @Test
-    fun testParseVulnerabilityReport_validJson_returnsCorrectData() {
+    fun testLoadVulnerabilityReport_validJson_returnsCorrectData() {
         val jsonString =
             """
             {
@@ -159,7 +133,7 @@
     }
 
     @Test(expected = IllegalArgumentException::class)
-    fun testParseVulnerabilityReport_invalidAsb_throwsIllegalArgumentException() {
+    fun testLoadVulnerabilityReport_invalidAsb_throwsIllegalArgumentException() {
         val jsonString =
             """
             {
@@ -181,21 +155,20 @@
     }
 
     @Test(expected = IllegalArgumentException::class)
-    fun testParseVulnerabilityReport_invalidJson_throwsIllegalArgumentException() {
+    fun testLoadVulnerabilityReport_invalidJson_throwsIllegalArgumentException() {
         val invalidJson = "{ invalid json }"
         securityState.loadVulnerabilityReport(invalidJson)
     }
 
     @RequiresApi(Build.VERSION_CODES.O)
+    @Config(sdk = [Build.VERSION_CODES.UPSIDE_DOWN_CAKE])
     @Test
     fun testGetVulnerabilityReportUrl_validSdkVersion_returnsCorrectUrl() {
         val sdkVersion = 34 // Android 14
         val baseUrl = SecurityPatchState.DEFAULT_VULNERABILITY_REPORTS_URL
-        val expectedUrl = "$baseUrl/v1/android_sdk_34.json"
+        val expectedUrl = "$baseUrl/v1/android_sdk_$sdkVersion.json"
 
-        doReturn(sdkVersion).`when`(mockSecurityStateManager).getAndroidSdkInt()
-
-        val actualUrl = securityState.getVulnerabilityReportUrl(Uri.parse(baseUrl)).toString()
+        val actualUrl = SecurityPatchState.getVulnerabilityReportUrl(Uri.parse(baseUrl)).toString()
         assertEquals(expectedUrl, actualUrl)
     }
 
@@ -205,7 +178,8 @@
         val bundle = Bundle()
         bundle.putString("system_spl", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
 
         val spl =
             securityState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
@@ -219,8 +193,8 @@
     fun testGetDeviceSpl_noSplAvailable_throwsIllegalStateException() {
         val bundle = Bundle()
         // SPL not set in the bundle for the system component
-        doReturn("").`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
-        doReturn(bundle).`when`(mockSecurityStateManager).getGlobalSecurityState(anyString())
+        doReturn("").`when`(mockSecurityStateManagerCompat).getPackageVersion(Mockito.anyString())
+        doReturn(bundle).`when`(mockSecurityStateManagerCompat).getGlobalSecurityState(anyString())
 
         securityState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
     }
@@ -231,6 +205,18 @@
     }
 
     @Test
+    fun testGetPublishedSpl_doesNotThrowWhenVulnerabilityReportLoadedFromConstructor() {
+        securityState =
+            SecurityPatchState(
+                mockContext,
+                listOf(),
+                mockSecurityStateManagerCompat,
+                vulnerabilityReportJsonString = generateMockReport("system", "2023-01-01")
+            )
+        securityState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
+    }
+
+    @Test
     fun testGetDeviceSpl_ReturnsCorrectSplForUnpatchedSystemModules() {
         val jsonInput =
             """
@@ -262,15 +248,19 @@
 
         securityState.loadVulnerabilityReport(jsonInput)
 
-        `when`(mockSecurityStateManager.getPackageVersion("com.google.android.modulemetadata"))
+        `when`(
+                mockSecurityStateManagerCompat.getPackageVersion(
+                    "com.google.android.modulemetadata"
+                )
+            )
             .thenReturn("2022-01-01")
-        `when`(mockSecurityStateManager.getPackageVersion("com.google.mainline.telemetry"))
+        `when`(mockSecurityStateManagerCompat.getPackageVersion("com.google.mainline.telemetry"))
             .thenReturn("2023-05-01")
-        `when`(mockSecurityStateManager.getPackageVersion("com.google.mainline.adservices"))
+        `when`(mockSecurityStateManagerCompat.getPackageVersion("com.google.mainline.adservices"))
             .thenReturn("2022-05-01")
-        `when`(mockSecurityStateManager.getPackageVersion("com.google.mainline.go.primary"))
+        `when`(mockSecurityStateManagerCompat.getPackageVersion("com.google.mainline.go.primary"))
             .thenReturn("2021-05-01")
-        `when`(mockSecurityStateManager.getPackageVersion("com.google.mainline.go.telemetry"))
+        `when`(mockSecurityStateManagerCompat.getPackageVersion("com.google.mainline.go.telemetry"))
             .thenReturn("2024-05-01")
 
         val spl =
@@ -779,8 +769,9 @@
         bundle.putString("kernel_version", "5.4.123")
         bundle.putString("com.google.android.modulemetadata", "2023-10-05")
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManagerCompat).getPackageVersion(anyString())
 
         val jsonInput =
             """
@@ -824,8 +815,9 @@
         bundle.putString("kernel_version", "5.4.123")
         bundle.putString("com.google.android.modulemetadata", "2023-10-05")
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManagerCompat).getPackageVersion(anyString())
 
         val jsonInput =
             """
@@ -869,8 +861,9 @@
         bundle.putString("kernel_version", "5.4.123")
         bundle.putString("com.google.android.modulemetadata", "2023-10-05")
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManagerCompat).getPackageVersion(anyString())
 
         val jsonInput =
             """
@@ -911,8 +904,9 @@
         bundle.putString("system_spl", "2022-01-01")
         bundle.putString("com.google.android.modulemetadata", "2023-10-05")
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn("2023-10-05").`when`(mockSecurityStateManager).getPackageVersion(anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn("2023-10-05").`when`(mockSecurityStateManagerCompat).getPackageVersion(anyString())
 
         val jsonInput =
             """
@@ -984,8 +978,11 @@
         bundle.putString("vendor_spl", systemSpl)
         bundle.putString("com.google.android.modulemetadata", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn(systemSpl)
+            .`when`(mockSecurityStateManagerCompat)
+            .getPackageVersion(Mockito.anyString())
 
         assertTrue(securityState.areCvesPatched(listOf("CVE-2023-0001", "CVE-2023-0002")))
     }
@@ -1027,8 +1024,11 @@
         bundle.putString("vendor_spl", systemSpl)
         bundle.putString("com.google.android.modulemetadata", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn(systemSpl)
+            .`when`(mockSecurityStateManagerCompat)
+            .getPackageVersion(Mockito.anyString())
 
         assertFalse(
             securityState.areCvesPatched(listOf("CVE-2023-0010", "CVE-2023-0001", "CVE-2023-0002"))
@@ -1072,8 +1072,11 @@
         bundle.putString("vendor_spl", systemSpl)
         bundle.putString("com.google.android.modulemetadata", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn(systemSpl)
+            .`when`(mockSecurityStateManagerCompat)
+            .getPackageVersion(Mockito.anyString())
 
         assertFalse(
             securityState.areCvesPatched(listOf("CVE-2024-1010", "CVE-2023-0001", "CVE-2023-0002"))
@@ -1118,8 +1121,11 @@
         bundle.putString("vendor_spl", systemSpl)
         bundle.putString("com.google.android.modulemetadata", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn(systemSpl)
+            .`when`(mockSecurityStateManagerCompat)
+            .getPackageVersion(Mockito.anyString())
 
         assertTrue(securityState.areCvesPatched(listOf("CVE-2023-0010")))
     }
@@ -1162,8 +1168,11 @@
         bundle.putString("vendor_spl", systemSpl)
         bundle.putString("com.google.android.modulemetadata", systemSpl)
 
-        `when`(mockSecurityStateManager.getGlobalSecurityState(anyString())).thenReturn(bundle)
-        doReturn(systemSpl).`when`(mockSecurityStateManager).getPackageVersion(Mockito.anyString())
+        `when`(mockSecurityStateManagerCompat.getGlobalSecurityState(anyString()))
+            .thenReturn(bundle)
+        doReturn(systemSpl)
+            .`when`(mockSecurityStateManagerCompat)
+            .getPackageVersion(Mockito.anyString())
 
         assertFalse(securityState.areCvesPatched(listOf("CVE-2023-0010")))
     }
diff --git a/security/security-state/src/test/java/androidx/security/state/SecurityStateManagerTest.kt b/security/security-state/src/test/java/androidx/security/state/SecurityStateManagerCompatTest.kt
similarity index 81%
rename from security/security-state/src/test/java/androidx/security/state/SecurityStateManagerTest.kt
rename to security/security-state/src/test/java/androidx/security/state/SecurityStateManagerCompatTest.kt
index 19c2f1d..961007a 100644
--- a/security/security-state/src/test/java/androidx/security/state/SecurityStateManagerTest.kt
+++ b/security/security-state/src/test/java/androidx/security/state/SecurityStateManagerCompatTest.kt
@@ -34,15 +34,15 @@
 import org.robolectric.annotation.Config
 
 @RunWith(JUnit4::class)
-class SecurityStateManagerTest {
+class SecurityStateManagerCompatTest {
 
     private val packageManager: PackageManager = mock<PackageManager>()
     private val context: Context = mock<Context>() { on { packageManager } doReturn packageManager }
-    private lateinit var securityStateManager: SecurityStateManager
+    private lateinit var securityStateManagerCompat: SecurityStateManagerCompat
 
     @Before
     fun setUp() {
-        securityStateManager = SecurityStateManager(context)
+        securityStateManagerCompat = SecurityStateManagerCompat(context)
     }
 
     @Config(minSdk = Build.VERSION_CODES.Q)
@@ -56,7 +56,7 @@
             .thenReturn(PackageInfo().apply { versionName = "" })
 
         val result =
-            securityStateManager.getGlobalSecurityState("com.google.android.modulemetadata")
+            securityStateManagerCompat.getGlobalSecurityState("com.google.android.modulemetadata")
         assertEquals(
             expectedBundle.getString("com.google.android.modulemetadata"),
             result.getString("com.google.android.modulemetadata")
@@ -68,7 +68,7 @@
         Mockito.`when`(packageManager.getPackageInfo(Mockito.anyString(), Mockito.eq(0)))
             .thenThrow(PackageManager.NameNotFoundException())
 
-        val result = securityStateManager.getPackageVersion("non.existent.package")
+        val result = securityStateManagerCompat.getPackageVersion("non.existent.package")
         assertTrue(result.isEmpty())
     }
 
@@ -77,25 +77,25 @@
         // This method would normally require reading from the file system,
         // but we can mock this by pretending the expected output of the file read is known.
         val originalKernelVersionMethod =
-            securityStateManager::class.java.getDeclaredMethod("getKernelVersion")
+            securityStateManagerCompat::class.java.getDeclaredMethod("getKernelVersion")
         originalKernelVersionMethod.isAccessible = true
-        val kernelVersion = originalKernelVersionMethod.invoke(securityStateManager) as String
+        val kernelVersion = originalKernelVersionMethod.invoke(securityStateManagerCompat) as String
         assertNotNull(kernelVersion)
     }
 
     @Test
     fun testGetVendorSpl() {
         val originalVendorSplMethod =
-            securityStateManager::class.java.getDeclaredMethod("getVendorSpl")
+            securityStateManagerCompat::class.java.getDeclaredMethod("getVendorSpl")
         originalVendorSplMethod.isAccessible = true
-        val vendorSpl = originalVendorSplMethod.invoke(securityStateManager) as String
+        val vendorSpl = originalVendorSplMethod.invoke(securityStateManagerCompat) as String
         assertNotNull(vendorSpl)
     }
 
     @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
     @Test
     fun testGetSecurityPatchLevelSafe_API_Level_Below_M() {
-        val result = securityStateManager.getSecurityPatchLevelSafe()
+        val result = securityStateManagerCompat.getSecurityPatchLevelSafe()
         assertEquals("", result)
     }
 }
diff --git a/settings.gradle b/settings.gradle
index 22a48cf..6597c4d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1159,6 +1159,8 @@
 includeProject(":work:work-rxjava3", [BuildType.MAIN])
 includeProject(":work:work-testing", [BuildType.MAIN])
 includeProject(":xr:arcore:arcore", [BuildType.XR])
+includeProject(":xr:arcore:integration-tests:whitebox", [BuildType.XR])
+includeProject(":xr:assets", [BuildType.XR])
 includeProject(":xr:compose:compose", [BuildType.XR])
 includeProject(":xr:compose:compose-testing", [BuildType.XR])
 includeProject(":xr:compose:material3:material3", [BuildType.XR])
diff --git a/sqlite/sqlite-bundled/api/api_lint.ignore b/sqlite/sqlite-bundled/api/api_lint.ignore
deleted file mode 100644
index 1ad4322..0000000
--- a/sqlite/sqlite-bundled/api/api_lint.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.driver.bundled.BundledSQLite:
-    Acronyms should not be capitalized in class names: was `BundledSQLite`, should this be `BundledSqLite`?
-AcronymName: androidx.sqlite.driver.bundled.BundledSQLiteDriver:
-    Acronyms should not be capitalized in class names: was `BundledSQLiteDriver`, should this be `BundledSqLiteDriver`?
diff --git a/sqlite/sqlite-framework/api/api_lint.ignore b/sqlite/sqlite-framework/api/api_lint.ignore
deleted file mode 100644
index 03491a3..0000000
--- a/sqlite/sqlite-framework/api/api_lint.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory:
-    Acronyms should not be capitalized in class names: was `FrameworkSQLiteOpenHelperFactory`, should this be `FrameworkSqLiteOpenHelperFactory`?
-AcronymName: androidx.sqlite.driver.AndroidSQLiteDriver:
-    Acronyms should not be capitalized in class names: was `AndroidSQLiteDriver`, should this be `AndroidSqLiteDriver`?
diff --git a/sqlite/sqlite-ktx/api/api_lint.ignore b/sqlite/sqlite-ktx/api/api_lint.ignore
deleted file mode 100644
index 3948bf5..0000000
--- a/sqlite/sqlite-ktx/api/api_lint.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AcronymName: androidx.sqlite.db.SupportSQLiteDatabaseKt:
-    Acronyms should not be capitalized in class names: was `SupportSQLiteDatabaseKt`, should this be `SupportSqLiteDatabaseKt`?
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
index 1939a45..4bf9c1b 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SimpleSQLiteQuery.android.kt
@@ -23,7 +23,6 @@
  * @param bindArgs The bind argument value that will replace the placeholders in the query.
  * @constructor Creates an SQL query with the sql string and the bind arguments.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public class SimpleSQLiteQuery(
     private val query: String,
     @Suppress("ArrayReturn") // Due to legacy API
@@ -45,7 +44,6 @@
      *
      * @param [statement] The SQL query to execute. Cannot include bind parameters.
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
     override fun bindTo(statement: SupportSQLiteProgram) {
         bind(statement, bindArgs)
     }
@@ -62,7 +60,6 @@
          */
         @JvmStatic
         public fun bind(
-            @Suppress("AcronymName") // SQL is a known term and should remain capitalized
             statement: SupportSQLiteProgram,
             @Suppress("ArrayReturn") // Due to legacy API
             bindArgs: Array<out Any?>?
@@ -78,12 +75,7 @@
             }
         }
 
-        private fun bind(
-            @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-            statement: SupportSQLiteProgram,
-            index: Int,
-            arg: Any?
-        ) {
+        private fun bind(statement: SupportSQLiteProgram, index: Int, arg: Any?) {
             // extracted from android.database.sqlite.SQLiteConnection
             if (arg == null) {
                 statement.bindNull(index)
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
index 5c6d9dd..ba6f65c 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteDatabase.android.kt
@@ -29,7 +29,6 @@
  * A database abstraction which removes the framework dependency and allows swapping underlying sql
  * versions. It mimics the behavior of [android.database.sqlite.SQLiteDatabase]
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteDatabase : Closeable {
     /**
      * Compiles the given SQL statement.
@@ -250,7 +249,6 @@
     public fun yieldIfContendedSafely(sleepAfterYieldDelayMillis: Long): Boolean
 
     /** Is true if [execPerConnectionSQL] is supported by the implementation. */
-    @get:Suppress("AcronymName") // To keep consistency with framework method name.
     public val isExecPerConnectionSQLSupported: Boolean
         get() = false
 
@@ -275,7 +273,6 @@
      * @throws UnsupportedOperationException if this operation is not supported. To check if it
      *   supported use [isExecPerConnectionSQLSupported]
      */
-    @Suppress("AcronymName") // To keep consistency with framework method name.
     public fun execPerConnectionSQL(
         sql: String,
         @SuppressLint("ArrayReturn") bindArgs: Array<out Any?>?
@@ -425,9 +422,7 @@
      *   not supported.
      * @throws SQLException if the SQL string is invalid
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-    @Throws(SQLException::class)
-    public fun execSQL(sql: String)
+    @Throws(SQLException::class) public fun execSQL(sql: String)
 
     /**
      * Execute a single SQL statement that does not return any data.
@@ -441,9 +436,7 @@
      * @param bindArgs only byte[], String, Long and Double are supported in selectionArgs.
      * @throws SQLException if the SQL string is invalid
      */
-    @Suppress("AcronymName") // SQL is a known term and should remain capitalized
-    @Throws(SQLException::class)
-    public fun execSQL(sql: String, bindArgs: Array<out Any?>)
+    @Throws(SQLException::class) public fun execSQL(sql: String, bindArgs: Array<out Any?>)
 
     /** Is true if the database is opened as read only. */
     public val isReadOnly: Boolean
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
index 2be3a94..c597f84 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteOpenHelper.android.kt
@@ -31,7 +31,6 @@
  * that class requires overriding certain methods, support implementation uses [Factory.create] to
  * create this and [Callback] to implement the methods that should be overridden.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteOpenHelper : Closeable {
     /**
      * Return the name of the SQLite database being opened, as given to the constructor. `null`
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
index 572879d..37965b1 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteProgram.android.kt
@@ -18,7 +18,6 @@
 import java.io.Closeable
 
 /** An interface to map the behavior of [android.database.sqlite.SQLiteProgram]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteProgram : Closeable {
     /**
      * Bind a NULL value to this statement. The value remains bound until [.clearBindings] is
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
index 3db42f5..657b85a3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQuery.android.kt
@@ -19,7 +19,6 @@
  * A query with typed bindings. It is better to use this API instead of
  * [android.database.sqlite.SQLiteDatabase.rawQuery] because it allows binding type safe parameters.
  */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteQuery {
     /** The SQL query. This query can have placeholders(?) for bind arguments. */
     public val sql: String
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
index 770820c..49ec1f3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteQueryBuilder.android.kt
@@ -18,7 +18,6 @@
 import java.util.regex.Pattern
 
 /** A simple query builder to create SQL SELECT queries. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public class SupportSQLiteQueryBuilder private constructor(private val table: String) {
     private var distinct = false
     private var columns: Array<out String>? = null
diff --git a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
index a5c36ae..bf1bca3 100644
--- a/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
+++ b/sqlite/sqlite/src/androidMain/kotlin/androidx/sqlite/db/SupportSQLiteStatement.android.kt
@@ -16,7 +16,6 @@
 package androidx.sqlite.db
 
 /** An interface to map the behavior of [android.database.sqlite.SQLiteStatement]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SupportSQLiteStatement : SupportSQLiteProgram {
     /**
      * Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
index 9b63cba..653b597 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLite.kt
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:Suppress("AcronymName") // SQL is a known term and should remain capitalized
 @file:JvmName("SQLite")
 
 package androidx.sqlite
@@ -53,13 +52,11 @@
 public annotation class DataType
 
 /** Executes a single SQL statement that returns no values. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public fun SQLiteConnection.execSQL(sql: String) {
     prepare(sql).use { it.step() }
 }
 
 /** Throws a [SQLiteException] with its message formed by the given [errorCode] amd [errorMsg]. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public fun throwSQLiteException(errorCode: Int, errorMsg: String?): Nothing {
     val message = buildString {
         append("Error code: $errorCode")
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
index 14b76d4..e988034 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteConnection.kt
@@ -24,7 +24,7 @@
  *
  * See also [Database Connection](https://www.sqlite.org/c3ref/sqlite3.html)
  */
-@Suppress("NotCloseable", "AcronymName") // SQL is a known term and should remain capitalized
+@Suppress("NotCloseable")
 public interface SQLiteConnection : AutoCloseable {
     /**
      * Prepares a new SQL statement.
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
index 5cb23bf..a1f3e50 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteDriver.kt
@@ -17,7 +17,6 @@
 package androidx.sqlite
 
 /** An interface to open database connections. */
-@Suppress("AcronymName") // SQL is a known term and should remain capitalized
 public interface SQLiteDriver {
     /**
      * Opens a new database connection.
diff --git a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
index 7f42c8b..8b319b9 100644
--- a/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
+++ b/sqlite/sqlite/src/commonMain/kotlin/androidx/sqlite/SQLiteStatement.kt
@@ -26,7 +26,7 @@
  *
  * See also [Prepared Statement](https://www.sqlite.org/c3ref/stmt.html)
  */
-@Suppress("NotCloseable", "AcronymName") // SQL is a known term and should remain capitalized
+@Suppress("NotCloseable")
 public interface SQLiteStatement : AutoCloseable {
     /**
      * Binds a ByteArray value to this statement at an index.
diff --git a/tvprovider/tvprovider/build.gradle b/tvprovider/tvprovider/build.gradle
index b3db8a6..cfe957e 100644
--- a/tvprovider/tvprovider/build.gradle
+++ b/tvprovider/tvprovider/build.gradle
@@ -13,6 +13,7 @@
 }
 
 dependencies {
+    api(libs.jspecify)
     api("androidx.annotation:annotation:1.8.1")
     api("androidx.core:core:1.1.0")
 
@@ -33,6 +34,4 @@
     inceptionYear = "2017"
     description = "Android Support Library for TV Provider"
     failOnDeprecationWarnings = false
-    // TODO: b/326456246
-    optOutJSpecify = true
 }
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/BaseProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/BaseProgram.java
index f387eab..c61fda7 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/BaseProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/BaseProgram.java
@@ -24,14 +24,15 @@
 import android.os.Build;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns;
 import androidx.tvprovider.media.tv.TvContractCompat.ProgramColumns;
 import androidx.tvprovider.media.tv.TvContractCompat.Programs;
 import androidx.tvprovider.media.tv.TvContractCompat.Programs.Genres.Genre;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -291,8 +292,7 @@
      * @return The series ID for the program.
      * @see androidx.tvprovider.media.tv.TvContractCompat.Programs#COLUMN_SERIES_ID
      */
-    @Nullable
-    public String getSeriesId() {
+    public @Nullable String getSeriesId() {
         return mValues.getAsString(Programs.COLUMN_SERIES_ID);
     }
 
@@ -918,8 +918,7 @@
          * @return This Builder object to allow for chaining of calls to builder methods.
          * @see androidx.tvprovider.media.tv.TvContractCompat.Programs#COLUMN_SERIES_ID
          */
-        @NonNull
-        public T setSeriesId(@Nullable String seriesId) {
+        public @NonNull T setSeriesId(@Nullable String seriesId) {
             mValues.put(ProgramColumns.COLUMN_SERIES_ID, seriesId);
             return (T) this;
         }
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Channel.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Channel.java
index ec1b720..2417f7a 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Channel.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Channel.java
@@ -23,13 +23,14 @@
 import android.net.Uri;
 import android.os.Build;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.Channels;
 import androidx.tvprovider.media.tv.TvContractCompat.Channels.ServiceType;
 import androidx.tvprovider.media.tv.TvContractCompat.Channels.VideoFormat;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.net.URISyntaxException;
 import java.nio.charset.Charset;
 
@@ -334,8 +335,7 @@
     /**
      * @return The value of {@link Channels#COLUMN_GLOBAL_CONTENT_ID} for the channel.
      */
-    @Nullable
-    public String getGlobalContentId() {
+    public @Nullable String getGlobalContentId() {
         return mValues.getAsString(Channels.COLUMN_GLOBAL_CONTENT_ID);
     }
 
@@ -1010,8 +1010,7 @@
          * @param value The value of {@link Channels#COLUMN_GLOBAL_CONTENT_ID} for the channel.
          * @return This Builder object to allow for chaining of calls to builder methods.
          */
-        @NonNull
-        public Builder setGlobalContentId(@NonNull String value) {
+        public @NonNull Builder setGlobalContentId(@NonNull String value) {
             mValues.put(Channels.COLUMN_GLOBAL_CONTENT_ID, value);
             return this;
         }
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/ChannelLogoUtils.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/ChannelLogoUtils.java
index 158e499..e789155 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/ChannelLogoUtils.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/ChannelLogoUtils.java
@@ -26,11 +26,11 @@
 import android.net.Uri;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
-import java.io.FileNotFoundException;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -151,10 +151,9 @@
      * @see #storeChannelLogo(Context, long, Uri)
      * @see #storeChannelLogo(Context, long, Bitmap)
      */
-    @Nullable
     @WorkerThread
     @SuppressLint("WrongThread") // TODO https://issuetracker.google.com/issues/116776070
-    public static Bitmap loadChannelLogo(@NonNull Context context, long channelId) {
+    public static @Nullable Bitmap loadChannelLogo(@NonNull Context context, long channelId) {
         Bitmap channelLogo = null;
         Uri logoUri = TvContract.buildChannelLogoUri(channelId);
         try (InputStream is = context.getContentResolver().openInputStream(logoUri)) {
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannel.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannel.java
index 26ad697..3a94489 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannel.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannel.java
@@ -29,12 +29,13 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.WorkerThread;
 import androidx.tvprovider.media.tv.TvContractCompat.Channels;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.io.FileNotFoundException;
 import java.net.URISyntaxException;
 import java.util.Objects;
@@ -397,8 +398,7 @@
          * @return This Builder object to allow for chaining of calls to builder methods.
          * @see TvContractCompat.Channels#COLUMN_DESCRIPTION
          */
-        @NonNull
-        public Builder setDescription(@Nullable CharSequence description) {
+        public @NonNull Builder setDescription(@Nullable CharSequence description) {
             if (description == null) {
                 mValues.remove(Channels.COLUMN_DESCRIPTION);
             } else {
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannelHelper.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannelHelper.java
index 93bdf2a..a23e685 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannelHelper.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewChannelHelper.java
@@ -30,11 +30,12 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.WorkerThread;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -222,8 +223,7 @@
      * @param channelId ID of preview channel in TvProvider
      * @return PreviewChannel or null if not found
      */
-    @Nullable
-    public PreviewChannel getPreviewChannel(long channelId) {
+    public @Nullable PreviewChannel getPreviewChannel(long channelId) {
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             return null;
@@ -415,8 +415,7 @@
     /**
      * Retrieves a single preview program from the system content provider (aka TvProvider).
      */
-    @Nullable
-    public PreviewProgram getPreviewProgram(long programId) {
+    public @Nullable PreviewProgram getPreviewProgram(long programId) {
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             return null;
@@ -494,8 +493,7 @@
     /**
      * Retrieves a single WatchNext program from the system content provider (aka TvProvider).
      */
-    @Nullable
-    public WatchNextProgram getWatchNextProgram(long programId) {
+    public @Nullable WatchNextProgram getWatchNextProgram(long programId) {
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
             return null;
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
index 2d03500..682efdb 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
@@ -21,10 +21,11 @@
 import android.database.Cursor;
 import android.os.Build;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.Objects;
 import java.util.Set;
 
@@ -83,8 +84,7 @@
      * query and in creating a Cursor object, which is used to iterate through the rows in the
      * table.
      */
-    @NonNull
-    public static final String[] PROJECTION = getProjection();
+    public static final String @NonNull [] PROJECTION = getProjection();
 
     private static final long INVALID_LONG_VALUE = -1;
     private static final int INVALID_INT_VALUE = -1;
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Program.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Program.java
index a9ba201..1892f75 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Program.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/Program.java
@@ -21,12 +21,13 @@
 import android.database.Cursor;
 import android.os.Build;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.Programs;
 import androidx.tvprovider.media.tv.TvContractCompat.Programs.Genres.Genre;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 /**
  * A convenience class to access {@link TvContractCompat.Programs} entries in the system content
  * provider.
@@ -141,8 +142,7 @@
      *
      * <p>No-op on devices prior to {@link android.os.Build.VERSION_CODES#R}.
      */
-    @Nullable
-    public String getGlobalContentId() {
+    public @Nullable String getGlobalContentId() {
         return mValues.getAsString(Programs.COLUMN_GLOBAL_CONTENT_ID);
     }
 
@@ -351,8 +351,7 @@
          * @param eventId The value of {@link Programs#COLUMN_EVENT_ID} for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
          */
-        @NonNull
-        public Builder setEventId(int eventId) {
+        public @NonNull Builder setEventId(int eventId) {
             mValues.put(Programs.COLUMN_EVENT_ID, eventId);
             return this;
         }
@@ -366,8 +365,7 @@
          *                    program.
          * @return This Builder object to allow for chaining of calls to builder methods.
          */
-        @NonNull
-        public Builder setGlobalContentId(@Nullable String globalContentId) {
+        public @NonNull Builder setGlobalContentId(@Nullable String globalContentId) {
             mValues.put(Programs.COLUMN_GLOBAL_CONTENT_ID, globalContentId);
             return this;
         }
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
index 4bf7e1f..2bfb681 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
@@ -32,12 +32,13 @@
 import android.provider.BaseColumns;
 import android.text.TextUtils;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.StringDef;
 import androidx.tvprovider.media.tv.TvContractCompat.Programs.Genres;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -1874,8 +1875,7 @@
          *         is not defined for the given video format.
          * @see #COLUMN_VIDEO_FORMAT
          */
-        @Nullable
-        public static String getVideoResolution(@VideoFormat String videoFormat) {
+        public static @Nullable String getVideoResolution(@VideoFormat String videoFormat) {
             return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
         }
 
@@ -2636,7 +2636,7 @@
              * @return an encoded genre string that can be inserted into the
              *         {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
              */
-            public static String encode(@NonNull @Genre String... genres) {
+            public static String encode(@Genre String @NonNull ... genres) {
                 if (genres == null) {
                     // MNC and before will throw a NPE.
                     return null;
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
index ad00cd6..58013e8 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
@@ -22,10 +22,11 @@
 import android.os.Build;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms;
 
+import org.jspecify.annotations.NonNull;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
@@ -86,8 +87,7 @@
      * query and in creating a Cursor object, which is used to iterate through the rows in the
      * table.
      */
-    @NonNull
-    public static final String[] PROJECTION = getProjection();
+    public static final String @NonNull [] PROJECTION = getProjection();
 
     private static final long INVALID_LONG_VALUE = -1;
 
diff --git a/wear/compose/compose-material3/api/current.txt b/wear/compose/compose-material3/api/current.txt
index 1fb47dc..ca1d072 100644
--- a/wear/compose/compose-material3/api/current.txt
+++ b/wear/compose/compose-material3/api/current.txt
@@ -1650,12 +1650,10 @@
   }
 
   public final class TimeTextDefaults {
-    method public float getAutoTextWeight();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.TimeSource rememberTimeSource(String timeFormat);
     method @androidx.compose.runtime.Composable public String timeFormat();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.text.TextStyle timeTextStyle(optional long background, optional long color, optional long fontSize);
-    property public final float AutoTextWeight;
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.foundation.CurvedTextStyle timeTextStyle(optional long background, optional long color, optional long fontSize);
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public static final float MaxSweepAngle;
     property public static final String TimeFormat12Hours;
@@ -1667,14 +1665,9 @@
   }
 
   public final class TimeTextKt {
-    method @androidx.compose.runtime.Composable public static void TimeText(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.foundation.CurvedModifier curvedModifier, optional float maxSweepAngle, optional androidx.wear.compose.material3.TimeSource timeSource, optional androidx.compose.ui.text.TextStyle timeTextStyle, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.wear.compose.material3.TimeTextScope,kotlin.Unit> content);
-  }
-
-  public abstract sealed class TimeTextScope {
-    method public abstract void composable(kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method public abstract void separator(optional androidx.compose.ui.text.TextStyle? style);
-    method public abstract void text(String text, optional androidx.compose.ui.text.TextStyle? style, optional float weight);
-    method public abstract void time();
+    method @androidx.compose.runtime.Composable public static void TimeText(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.foundation.CurvedModifier curvedModifier, optional float maxSweepAngle, optional androidx.wear.compose.material3.TimeSource timeSource, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function2<? super androidx.wear.compose.foundation.CurvedScope,? super java.lang.String,kotlin.Unit> content);
+    method public static void timeTextCurvedText(androidx.wear.compose.foundation.CurvedScope, String time, optional androidx.wear.compose.foundation.CurvedTextStyle? style);
+    method public static void timeTextSeparator(androidx.wear.compose.foundation.CurvedScope, optional androidx.wear.compose.foundation.CurvedTextStyle? curvedTextStyle, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding);
   }
 
   public final class TouchTargetAwareSizeKt {
diff --git a/wear/compose/compose-material3/api/restricted_current.txt b/wear/compose/compose-material3/api/restricted_current.txt
index 1fb47dc..ca1d072 100644
--- a/wear/compose/compose-material3/api/restricted_current.txt
+++ b/wear/compose/compose-material3/api/restricted_current.txt
@@ -1650,12 +1650,10 @@
   }
 
   public final class TimeTextDefaults {
-    method public float getAutoTextWeight();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.TimeSource rememberTimeSource(String timeFormat);
     method @androidx.compose.runtime.Composable public String timeFormat();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.text.TextStyle timeTextStyle(optional long background, optional long color, optional long fontSize);
-    property public final float AutoTextWeight;
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.foundation.CurvedTextStyle timeTextStyle(optional long background, optional long color, optional long fontSize);
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property public static final float MaxSweepAngle;
     property public static final String TimeFormat12Hours;
@@ -1667,14 +1665,9 @@
   }
 
   public final class TimeTextKt {
-    method @androidx.compose.runtime.Composable public static void TimeText(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.foundation.CurvedModifier curvedModifier, optional float maxSweepAngle, optional androidx.wear.compose.material3.TimeSource timeSource, optional androidx.compose.ui.text.TextStyle timeTextStyle, optional long contentColor, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.wear.compose.material3.TimeTextScope,kotlin.Unit> content);
-  }
-
-  public abstract sealed class TimeTextScope {
-    method public abstract void composable(kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method public abstract void separator(optional androidx.compose.ui.text.TextStyle? style);
-    method public abstract void text(String text, optional androidx.compose.ui.text.TextStyle? style, optional float weight);
-    method public abstract void time();
+    method @androidx.compose.runtime.Composable public static void TimeText(optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.foundation.CurvedModifier curvedModifier, optional float maxSweepAngle, optional androidx.wear.compose.material3.TimeSource timeSource, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function2<? super androidx.wear.compose.foundation.CurvedScope,? super java.lang.String,kotlin.Unit> content);
+    method public static void timeTextCurvedText(androidx.wear.compose.foundation.CurvedScope, String time, optional androidx.wear.compose.foundation.CurvedTextStyle? style);
+    method public static void timeTextSeparator(androidx.wear.compose.foundation.CurvedScope, optional androidx.wear.compose.foundation.CurvedTextStyle? curvedTextStyle, optional androidx.wear.compose.foundation.ArcPaddingValues contentArcPadding);
   }
 
   public final class TouchTargetAwareSizeKt {
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScrollAwayDemos.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScrollAwayDemos.kt
index ce9aa66..9b3d8c3 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScrollAwayDemos.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ScrollAwayDemos.kt
@@ -41,6 +41,7 @@
 import androidx.wear.compose.material3.ScreenStage
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.TimeText
+import androidx.wear.compose.material3.curvedText
 import androidx.wear.compose.material3.samples.ScrollAwaySample
 import androidx.wear.compose.material3.scrollAway
 
@@ -100,7 +101,7 @@
                         else ScreenStage.Idle
                     }
                 ),
-            content = { text("ScrollAway") }
+            content = { curvedText("ScrollAway") }
         )
     }
 }
@@ -151,7 +152,7 @@
                         else ScreenStage.Idle
                     }
                 ),
-            content = { text("ScrollAway") }
+            content = { curvedText("ScrollAway") }
         )
     }
 }
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/TimeTextDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/TimeTextDemo.kt
index 397f24d..d53c350 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/TimeTextDemo.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/TimeTextDemo.kt
@@ -33,6 +33,7 @@
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import androidx.wear.compose.foundation.curvedComposable
 import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
 import androidx.wear.compose.integration.demos.common.ComposableDemo
 import androidx.wear.compose.material3.Button
@@ -43,13 +44,17 @@
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.TimeText
 import androidx.wear.compose.material3.TimeTextDefaults
+import androidx.wear.compose.material3.curvedText
 import androidx.wear.compose.material3.samples.TimeTextClockOnly
 import androidx.wear.compose.material3.samples.TimeTextWithStatus
+import androidx.wear.compose.material3.samples.TimeTextWithStatusEllipsized
+import androidx.wear.compose.material3.timeTextSeparator
 
 val TimeTextDemos =
     listOf(
         ComposableDemo("Clock only") { TimeTextClockOnly() },
         ComposableDemo("Clock with Status") { TimeTextWithStatus() },
+        ComposableDemo("Clock with Ellipsized Status") { TimeTextWithStatusEllipsized() },
         ComposableDemo("Clock with long Status") { TimeTextWithLongStatus() },
         ComposableDemo("Clock with Icon") { TimeTextWithIcon() },
         ComposableDemo("Clock with custom colors") { TimeTextWithCustomColors() },
@@ -61,10 +66,10 @@
 
 @Composable
 fun TimeTextWithLongStatus() {
-    TimeText {
-        text("Some long leading text")
-        separator()
-        time()
+    TimeText { time ->
+        curvedText("Some long leading text")
+        timeTextSeparator()
+        curvedText(time)
     }
 }
 
@@ -72,12 +77,12 @@
 fun TimeTextWithCustomColors() {
     val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
 
-    TimeText {
-        text("ETA", customStyle)
-        composable { Spacer(modifier = Modifier.size(4.dp)) }
-        text("12:48")
-        separator()
-        time()
+    TimeText { time ->
+        curvedText("ETA", style = customStyle)
+        curvedComposable { Spacer(modifier = Modifier.size(4.dp)) }
+        curvedText("12:48")
+        timeTextSeparator()
+        curvedText(time)
     }
 }
 
@@ -85,19 +90,19 @@
 fun TimeTextCustomSize() {
     val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Green, fontSize = 24.sp)
 
-    TimeText {
-        text("ETA", customStyle)
-        separator()
-        time()
+    TimeText { time ->
+        curvedText("ETA", style = customStyle)
+        timeTextSeparator()
+        curvedText(time)
     }
 }
 
 @Composable
 fun TimeTextWithIcon() {
-    TimeText {
-        time()
-        separator()
-        composable {
+    TimeText { time ->
+        curvedText(time)
+        timeTextSeparator()
+        curvedComposable {
             Icon(
                 imageVector = Icons.Filled.Favorite,
                 contentDescription = "Favorite",
@@ -151,13 +156,13 @@
             items(10) { Text("Some extra items ($it) to scroll", Modifier.padding(5.dp)) }
         }
         // Timetext later so it's on top.
-        TimeText { time() }
+        TimeText { time -> curvedText(time) }
     }
 }
 
 @Composable
 fun TimeTextOnScreenWhiteBackground() {
-    Box(Modifier.fillMaxSize().background(Color.White)) { TimeText { time() } }
+    Box(Modifier.fillMaxSize().background(Color.White)) { TimeText { time -> curvedText(time) } }
 }
 
 @Composable
@@ -166,7 +171,7 @@
         MaterialTheme(
             colorScheme = MaterialTheme.colorScheme.copy(background = Color.Transparent)
         ) {
-            TimeText { time() }
+            TimeText { time -> curvedText(time) }
         }
     }
 }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/DatePickerBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/DatePickerBenchmark.kt
index 51431d0..fe612b2 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/DatePickerBenchmark.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/DatePickerBenchmark.kt
@@ -84,13 +84,8 @@
             device.waitForIdle()
             SystemClock.sleep(500)
             repeat(3) { columnIndex ->
-                repeat(2) { i ->
-                    val endY =
-                        if (i % 2 == 0) {
-                            device.displayHeight / 10 // scroll up
-                        } else {
-                            device.displayHeight * 9 / 10 // scroll down
-                        }
+                repeat(20) {
+                    val endY = device.displayHeight * 9 / 10 // scroll down
                     device.swipe(
                         device.displayWidth / 2,
                         device.displayHeight / 2,
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/PickerBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/PickerBenchmark.kt
index 280b461..5e89683 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/PickerBenchmark.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/PickerBenchmark.kt
@@ -45,13 +45,8 @@
 
     override val exercise: MacrobenchmarkScope.() -> Unit
         get() = {
-            repeat(4) { i ->
-                val endY =
-                    if (i % 2 == 0) {
-                        device.displayHeight / 10 // scroll up
-                    } else {
-                        device.displayHeight * 9 / 10 // scroll down
-                    }
+            repeat(20) {
+                val endY = device.displayHeight * 9 / 10 // scroll down
                 device.swipe(
                     device.displayWidth / 2,
                     device.displayHeight / 2,
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/ScalingLazyColumnBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/ScalingLazyColumnBenchmark.kt
new file mode 100644
index 0000000..37f0dab
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/ScalingLazyColumnBenchmark.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.macrobenchmark.common
+
+import android.os.SystemClock
+import androidx.benchmark.macro.MacrobenchmarkScope
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
+import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
+import androidx.wear.compose.material3.AppScaffold
+import androidx.wear.compose.material3.EdgeButton
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.ScreenScaffold
+import androidx.wear.compose.material3.Text
+import kotlinx.coroutines.launch
+
+val ScalingLazyColumnBenchmark =
+    object : MacrobenchmarkScreen {
+        override val content: @Composable (BoxScope.() -> Unit)
+            get() = {
+                val state = rememberScalingLazyListState()
+                val coroutineScope = rememberCoroutineScope()
+                AppScaffold {
+                    ScreenScaffold(
+                        state,
+                        contentPadding = PaddingValues(horizontal = 10.dp, vertical = 20.dp),
+                        edgeButton = {
+                            EdgeButton(
+                                onClick = { coroutineScope.launch { state.scrollToItem(1) } }
+                            ) {
+                                Text("To top")
+                            }
+                        }
+                    ) { contentPadding ->
+                        ScalingLazyColumn(
+                            horizontalAlignment = Alignment.CenterHorizontally,
+                            contentPadding = contentPadding,
+                            state = state,
+                            modifier =
+                                Modifier.background(MaterialTheme.colorScheme.background)
+                                    .semantics { contentDescription = CONTENT_DESCRIPTION }
+                        ) {
+                            items(5000) {
+                                Text(
+                                    "Item $it",
+                                    color = MaterialTheme.colorScheme.onSurface,
+                                    style = MaterialTheme.typography.bodyLarge,
+                                    modifier = Modifier.fillMaxWidth().padding(10.dp)
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+
+        override val exercise: MacrobenchmarkScope.() -> Unit
+            get() = {
+                repeat(20) {
+                    val endY = device.displayHeight * 9 / 10 // scroll down
+
+                    device.swipe(
+                        device.displayWidth / 2,
+                        device.displayHeight / 2,
+                        device.displayWidth / 2,
+                        endY,
+                        10
+                    )
+                    device.waitForIdle()
+                    SystemClock.sleep(500)
+                }
+            }
+    }
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TimePickerBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TimePickerBenchmark.kt
index 7d15ce7..aad5c48 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TimePickerBenchmark.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TimePickerBenchmark.kt
@@ -39,14 +39,9 @@
 
     override val exercise: MacrobenchmarkScope.() -> Unit
         get() = {
-            repeat(4) { i ->
+            repeat(20) {
                 val startY = device.displayHeight / 2
-                val endY =
-                    if (i % 2 == 0) {
-                        device.displayHeight / 10 // scroll up
-                    } else {
-                        device.displayHeight * 9 / 10 // scroll down
-                    }
+                val endY = device.displayHeight * 9 / 10 // scroll down
 
                 val hourX = device.displayWidth / 4
                 device.swipe(hourX, startY, hourX, endY, 10)
diff --git a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt
index bc24b82..dae1ab0 100644
--- a/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt
+++ b/wear/compose/compose-material3/macrobenchmark-common/src/main/java/androidx/wear/compose/material3/macrobenchmark/common/TransformingLazyColumnBenchmark.kt
@@ -16,7 +16,7 @@
 
 package androidx.wear.compose.material3.macrobenchmark.common
 
-import android.graphics.Point
+import android.os.SystemClock
 import androidx.benchmark.macro.MacrobenchmarkScope
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.BoxScope
@@ -29,7 +29,6 @@
 import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
-import androidx.test.uiautomator.By
 import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
 import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
 import androidx.wear.compose.material3.AppScaffold
@@ -89,12 +88,17 @@
 
         override val exercise: MacrobenchmarkScope.() -> Unit
             get() = {
-                val list = device.findObject(By.desc(CONTENT_DESCRIPTION))
-                // Setting a gesture margin is important otherwise gesture nav is triggered.
-                list.setGestureMargin(device.displayWidth / 5)
-                repeat(5) {
-                    list.drag(Point(list.visibleCenter.x, list.visibleCenter.y / 3))
+                repeat(20) {
+                    val endY = device.displayHeight * 9 / 10 // scroll down
+                    device.swipe(
+                        device.displayWidth / 2,
+                        device.displayHeight / 2,
+                        device.displayWidth / 2,
+                        endY,
+                        10
+                    )
                     device.waitForIdle()
+                    SystemClock.sleep(500)
                 }
             }
     }
diff --git a/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml b/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
index 6ec1884..0127c6d 100644
--- a/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/wear/compose/compose-material3/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -225,6 +225,17 @@
         </activity>
 
         <activity
+            android:name=".ScalingLazyColumnActivity"
+            android:theme="@style/AppTheme"
+            android:exported="true">
+            <intent-filter>
+                <action android:name=
+                    "androidx.wear.compose.material3.macrobenchmark.target.SCALING_LAZY_COLUMN_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity
             android:name=".SliderActivity"
             android:theme="@style/AppTheme"
             android:exported="true">
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java b/wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/ScalingLazyColumnActivity.kt
similarity index 65%
copy from navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
copy to wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/ScalingLazyColumnActivity.kt
index f3a5276..0fafcad 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/test/TestEnum.java
+++ b/wear/compose/compose-material3/macrobenchmark-target/src/main/java/androidx/wear/compose/material3/macrobenchmark/target/ScalingLazyColumnActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-package androidx.navigation.test;
+package androidx.wear.compose.material3.macrobenchmark.target
 
-public enum TestEnum {
-    VALUE_ONE, VALUE_TWO
-}
+import androidx.wear.compose.material3.macrobenchmark.common.ScalingLazyColumnBenchmark
+
+class ScalingLazyColumnActivity : BenchmarkBaseActivity(ScalingLazyColumnBenchmark)
diff --git a/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/ScalingLazyColumnBenchmarkTest.kt b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/ScalingLazyColumnBenchmarkTest.kt
new file mode 100644
index 0000000..d3b0172
--- /dev/null
+++ b/wear/compose/compose-material3/macrobenchmark/src/main/java/androidx/wear/compose/material3/macrobenchmark/ScalingLazyColumnBenchmarkTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.macrobenchmark
+
+import androidx.benchmark.macro.CompilationMode
+import androidx.test.filters.LargeTest
+import androidx.wear.compose.material3.macrobenchmark.common.ScalingLazyColumnBenchmark
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class ScalingLazyColumnBenchmarkTest(compilationMode: CompilationMode) :
+    BenchmarkTestBase(
+        compilationMode = compilationMode,
+        macrobenchmarkScreen = ScalingLazyColumnBenchmark,
+        actionSuffix = "SCALING_LAZY_COLUMN_ACTIVITY"
+    )
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ScrollAwaySample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ScrollAwaySample.kt
index 225dd56f..42f1ba7 100644
--- a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ScrollAwaySample.kt
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ScrollAwaySample.kt
@@ -33,7 +33,9 @@
 import androidx.wear.compose.material3.ScreenStage
 import androidx.wear.compose.material3.Text
 import androidx.wear.compose.material3.TimeText
+import androidx.wear.compose.material3.curvedText
 import androidx.wear.compose.material3.scrollAway
+import androidx.wear.compose.material3.timeTextSeparator
 
 @Sampled
 @Composable
@@ -73,10 +75,10 @@
                         if (state.isScrollInProgress) ScreenStage.Scrolling else ScreenStage.Idle
                     }
                 ),
-            content = {
-                text("ScrollAway")
-                separator()
-                time()
+            content = { time ->
+                curvedText("ScrollAway")
+                timeTextSeparator()
+                curvedText(time)
             }
         )
     }
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/TimeTextSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/TimeTextSample.kt
index 020e098..47ba1e6 100644
--- a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/TimeTextSample.kt
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/TimeTextSample.kt
@@ -18,9 +18,14 @@
 
 import androidx.annotation.Sampled
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.wear.compose.foundation.CurvedModifier
+import androidx.wear.compose.foundation.weight
 import androidx.wear.compose.material3.MaterialTheme
 import androidx.wear.compose.material3.TimeText
 import androidx.wear.compose.material3.TimeTextDefaults
+import androidx.wear.compose.material3.curvedText
+import androidx.wear.compose.material3.timeTextSeparator
 
 @Sampled
 @Composable
@@ -34,9 +39,23 @@
 fun TimeTextWithStatus() {
     val primaryStyle =
         TimeTextDefaults.timeTextStyle(color = MaterialTheme.colorScheme.primaryContainer)
-    TimeText {
-        text("ETA 12:48", style = primaryStyle)
-        separator()
-        time()
+    TimeText { time ->
+        curvedText("ETA 12:48", style = primaryStyle)
+        timeTextSeparator()
+        curvedText(time)
+    }
+}
+
+@Sampled
+@Composable
+fun TimeTextWithStatusEllipsized() {
+    TimeText { time ->
+        curvedText(
+            "Long status that should be ellipsized.",
+            CurvedModifier.weight(1f),
+            overflow = TextOverflow.Ellipsis
+        )
+        timeTextSeparator()
+        curvedText(time)
     }
 }
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ScrollAwayTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ScrollAwayTest.kt
index 90674cb..4849bdc 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ScrollAwayTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ScrollAwayTest.kt
@@ -48,6 +48,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.wear.compose.foundation.ScrollInfoProvider
+import androidx.wear.compose.foundation.curvedComposable
 import androidx.wear.compose.foundation.lazy.AutoCenteringParams
 import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
 import androidx.wear.compose.foundation.lazy.ScalingLazyListState
@@ -207,7 +208,7 @@
                             )
                             .testTag(TIME_TEXT_TAG),
                 ) {
-                    composable { Box(Modifier.size(20.dp).background(timeTextColor)) }
+                    curvedComposable { Box(Modifier.size(20.dp).background(timeTextColor)) }
                 }
             }
         }
@@ -233,7 +234,7 @@
                             )
                             .testTag(TIME_TEXT_TAG)
                 ) {
-                    composable { Box(Modifier.size(20.dp).background(timeTextColor)) }
+                    curvedComposable { Box(Modifier.size(20.dp).background(timeTextColor)) }
                 }
                 LazyColumn(state = scrollState, modifier = Modifier.testTag(SCROLL_TAG)) {
                     item { ListHeader { Text("Buttons") } }
@@ -253,7 +254,6 @@
                         .testTag(TEST_TAG)
             ) {
                 TimeText(
-                    contentColor = timeTextColor,
                     modifier =
                         Modifier.scrollAway(
                                 scrollInfoProvider = ScrollInfoProvider(scrollState),
@@ -264,7 +264,7 @@
                             )
                             .testTag(TIME_TEXT_TAG)
                 ) {
-                    composable { Box(Modifier.size(20.dp).background(timeTextColor)) }
+                    curvedComposable { Box(Modifier.size(20.dp).background(timeTextColor)) }
                 }
                 Column(modifier = Modifier.verticalScroll(scrollState).testTag(SCROLL_TAG)) {
                     ListHeader { Text("Buttons") }
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextScreenshotTest.kt
index 5c81306..526b932 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextScreenshotTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextScreenshotTest.kt
@@ -29,23 +29,25 @@
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.DeviceConfigurationOverride
 import androidx.compose.ui.test.ForcedSize
-import androidx.compose.ui.test.RoundScreen
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.then
+import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.screenshot.AndroidXScreenshotTestRule
-import com.google.testing.junit.testparameterinjector.TestParameter
-import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import androidx.wear.compose.foundation.CurvedModifier
+import androidx.wear.compose.foundation.CurvedScope
+import androidx.wear.compose.foundation.curvedComposable
+import androidx.wear.compose.foundation.weight
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TestName
 import org.junit.runner.RunWith
 
 @MediumTest
-@RunWith(TestParameterInjector::class)
+@RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
 class TimeTextScreenshotTest {
     @get:Rule val rule = createComposeRule()
@@ -60,60 +62,34 @@
         }
 
     @Test
-    fun time_text_with_clock_only_on_round_device() = verifyScreenshot {
+    fun time_text_with_clock_only() = verifyScreenshot {
         TimeText(
             modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
             timeSource = MockTimeSource,
-        ) {
-            time()
+        )
+    }
+
+    @Test
+    fun time_text_with_status() = verifyScreenshot {
+        TimeText(
+            modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
+            timeSource = MockTimeSource,
+        ) { time ->
+            curvedText("ETA 12:48")
+            timeTextSeparator()
+            curvedText(time)
         }
     }
 
     @Test
-    fun time_text_with_clock_only_on_non_round_device() =
-        verifyScreenshot(false) {
-            TimeText(
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_with_status_on_round_device() = verifyScreenshot {
+    fun time_text_with_icon() = verifyScreenshot {
         TimeText(
             modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
             timeSource = MockTimeSource,
-        ) {
-            text("ETA 12:48")
-            separator()
-            time()
-        }
-    }
-
-    @Test
-    fun time_text_with_status_on_non_round_device() =
-        verifyScreenshot(false) {
-            TimeText(
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                text("ETA 12:48")
-                separator()
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_with_icon_on_round_device() = verifyScreenshot {
-        TimeText(
-            modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-            timeSource = MockTimeSource,
-        ) {
-            time()
-            separator()
-            composable {
+        ) { time ->
+            curvedText(time)
+            timeTextSeparator()
+            curvedComposable {
                 Icon(
                     imageVector = Icons.Filled.Favorite,
                     contentDescription = "Favorite",
@@ -124,193 +100,126 @@
     }
 
     @Test
-    fun time_text_with_icon_on_non_round_device() =
-        verifyScreenshot(false) {
-            TimeText(
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                time()
-                separator()
-                composable {
-                    Icon(
-                        imageVector = Icons.Filled.Favorite,
-                        contentDescription = "Favorite",
-                        modifier = Modifier.size(13.dp)
-                    )
-                }
-            }
-        }
-
-    @Test
-    fun time_text_with_custom_colors_on_round_device() = verifyScreenshot {
+    fun time_text_with_custom_colors() = verifyScreenshot {
         val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
         val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
         val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
         TimeText(
-            contentColor = Color.Green,
-            timeTextStyle = timeTextStyle,
             modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
             timeSource = MockTimeSource,
-        ) {
-            text("ETA", customStyle)
-            composable { Spacer(modifier = Modifier.size(4.dp)) }
-            text("12:48")
-            separator(separatorStyle)
-            time()
+        ) { time ->
+            curvedText("ETA 12:48", style = customStyle)
+            curvedComposable { Spacer(modifier = Modifier.size(4.dp)) }
+            curvedText("12:48", style = customStyle)
+            timeTextSeparator(separatorStyle)
+            curvedText(time, style = timeTextStyle)
         }
     }
 
     @Test
-    fun time_text_with_long_status_on_round_device() = verifyScreenshot {
+    fun time_text_with_long_status() = verifyScreenshot {
         val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Green)
         TimeText(
-            contentColor = Color.Green,
-            timeTextStyle = timeTextStyle,
             modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
             timeSource = MockTimeSource,
-        ) {
-            text("Long status that should be ellipsized.")
-            composable { Spacer(modifier = Modifier.size(4.dp)) }
-            time()
-        }
-    }
-
-    @Test
-    fun time_text_with_custom_colors_on_non_round_device() =
-        verifyScreenshot(false) {
-            val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
-            val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
-            val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
-            TimeText(
-                contentColor = Color.Green,
-                timeTextStyle = timeTextStyle,
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                text("ETA", customStyle)
-                composable { Spacer(modifier = Modifier.size(4.dp)) }
-                text("12:48")
-                separator(separatorStyle)
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_with_very_long_text_on_round_device() =
-        verifyScreenshot(true) {
-            val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
-            val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
-            val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
-            TimeText(
-                contentColor = Color.Green,
-                timeTextStyle = timeTextStyle,
-                maxSweepAngle = 180f,
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                text(
-                    "Very long text to ensure we are respecting the maxSweep parameter",
-                    customStyle
-                )
-                separator(separatorStyle)
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_with_very_long_text_non_round_device() =
-        verifyScreenshot(false) {
-            val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
-            val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
-            val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
-            TimeText(
-                contentColor = Color.Green,
-                timeTextStyle = timeTextStyle,
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                text(
-                    "Very long text to ensure we are not taking more than one line and " +
-                        "leaving room for the time",
-                    customStyle
-                )
-                separator(separatorStyle)
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_with_very_long_text_smaller_angle_on_round_device() =
-        verifyScreenshot(true) {
-            val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
-            val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
-            val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
-            TimeText(
-                contentColor = Color.Green,
-                timeTextStyle = timeTextStyle,
-                maxSweepAngle = 90f,
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-            ) {
-                text(
-                    "Very long text to ensure we are respecting the maxSweep parameter",
-                    customStyle
-                )
-                separator(separatorStyle)
-                time()
-            }
-        }
-
-    @Test
-    fun time_text_long_text_before_time(@TestParameter shape: ScreenShape) =
-        TimeTextWithDefaults(shape.isRound) {
-            text("Very long text to ensure we are respecting the weight parameter", weight = 1f)
-            separator()
-            time()
-            separator()
-            text("More")
-        }
-
-    @Test
-    fun time_text_long_text_after_time(@TestParameter shape: ScreenShape) =
-        TimeTextWithDefaults(shape.isRound) {
-            text("More")
-            separator()
-            time()
-            separator()
-            text("Very long text to ensure we are respecting the weight parameter", weight = 1f)
-        }
-
-    // This is to get better names, so it says 'round_device' instead of 'true'
-    enum class ScreenShape(val isRound: Boolean) {
-        ROUND_DEVICE(true),
-        SQUARE_DEVICE(false)
-    }
-
-    private fun TimeTextWithDefaults(isDeviceRound: Boolean, content: TimeTextScope.() -> Unit) =
-        verifyScreenshot(isDeviceRound) {
-            TimeText(
-                contentColor = Color.Green,
-                maxSweepAngle = 180f,
-                modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
-                timeSource = MockTimeSource,
-                content = content
+        ) { time ->
+            curvedText(
+                "Long status that should be ellipsized.",
+                CurvedModifier.weight(1f),
+                overflow = TextOverflow.Ellipsis,
+                style = timeTextStyle
             )
+            curvedComposable { Spacer(modifier = Modifier.size(4.dp)) }
+            curvedText(time, style = timeTextStyle)
         }
+    }
 
-    private fun verifyScreenshot(isDeviceRound: Boolean = true, content: @Composable () -> Unit) {
+    @Test
+    fun time_text_with_very_long_text() = verifyScreenshot {
+        val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
+        val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
+        val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
+        TimeText(
+            maxSweepAngle = 180f,
+            modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
+            timeSource = MockTimeSource,
+        ) { time ->
+            curvedText(
+                "Very long text to ensure we are respecting the maxSweep parameter",
+                CurvedModifier.weight(1f),
+                overflow = TextOverflow.Ellipsis,
+                maxSweepAngle = 180f,
+                style = customStyle
+            )
+            timeTextSeparator(separatorStyle)
+            curvedText(time, style = timeTextStyle)
+        }
+    }
+
+    @Test
+    fun time_text_with_very_long_text_smaller_angle() = verifyScreenshot {
+        val customStyle = TimeTextDefaults.timeTextStyle(color = Color.Red)
+        val timeTextStyle = TimeTextDefaults.timeTextStyle(color = Color.Cyan)
+        val separatorStyle = TimeTextDefaults.timeTextStyle(color = Color.Yellow)
+        TimeText(
+            maxSweepAngle = 90f,
+            modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
+            timeSource = MockTimeSource,
+        ) { time ->
+            curvedText(
+                "Very long text to ensure we are respecting the maxSweep parameter",
+                CurvedModifier.weight(1f),
+                overflow = TextOverflow.Ellipsis,
+                style = customStyle
+            )
+            timeTextSeparator(separatorStyle)
+            curvedText(time, style = timeTextStyle)
+        }
+    }
+
+    @Test
+    fun time_text_long_text_before_time() = TimeTextWithDefaults { time ->
+        curvedText(
+            "Very long text to ensure we are respecting the weight parameter",
+            CurvedModifier.weight(1f),
+            overflow = TextOverflow.Ellipsis
+        )
+        timeTextSeparator()
+        curvedText(time)
+        timeTextSeparator()
+        curvedText("More")
+    }
+
+    @Test
+    fun time_text_long_text_after_time() = TimeTextWithDefaults { time ->
+        curvedText("More")
+        timeTextSeparator()
+        curvedText(time)
+        timeTextSeparator()
+        curvedText(
+            "Very long text to ensure we are respecting the weight parameter",
+            CurvedModifier.weight(1f),
+            overflow = TextOverflow.Ellipsis
+        )
+    }
+
+    private fun TimeTextWithDefaults(content: CurvedScope.(String) -> Unit) = verifyScreenshot {
+        TimeText(
+            maxSweepAngle = 180f,
+            modifier = Modifier.testTag(TEST_TAG).background(Color.DarkGray),
+            timeSource = MockTimeSource,
+            content = content
+        )
+    }
+
+    private fun verifyScreenshot(content: @Composable () -> Unit) {
         rule.verifyScreenshot(
-            // Valid characters for golden identifiers are [A-Za-z0-9_-]
-            // TestParameterInjector adds '[' + parameter_values + ']' to the test name.
-            methodName = testName.methodName.replace("[", "_").replace("]", ""),
+            methodName = testName.methodName,
             screenshotRule = screenshotRule,
             content = {
                 val screenSize = LocalContext.current.resources.configuration.smallestScreenWidthDp
                 DeviceConfigurationOverride(
-                    DeviceConfigurationOverride.ForcedSize(
-                        DpSize(screenSize.dp, screenSize.dp)
-                    ) then DeviceConfigurationOverride.RoundScreen(isDeviceRound)
+                    DeviceConfigurationOverride.ForcedSize(DpSize(screenSize.dp, screenSize.dp))
                 ) {
                     content()
                 }
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextTest.kt
index f932e4a..e8a7528 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextTest.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TimeTextTest.kt
@@ -21,20 +21,13 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.DeviceConfigurationOverride
-import androidx.compose.ui.test.RoundScreen
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithTag
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontStyle
-import androidx.compose.ui.unit.sp
 import androidx.test.filters.SdkSuppress
+import androidx.wear.compose.foundation.curvedComposable
 import java.util.Calendar
 import java.util.Locale
 import java.util.TimeZone
@@ -47,101 +40,54 @@
 
     @Test
     fun supports_testtag() {
-        rule.setContentWithTheme { TimeText(modifier = Modifier.testTag(TEST_TAG)) { time() } }
+        rule.setContentWithTheme { TimeText(modifier = Modifier.testTag(TEST_TAG)) }
 
         rule.onNodeWithTag(TEST_TAG).assertExists()
     }
 
     @Test
-    fun shows_time_by_default_on_non_round_device() {
+    fun shows_time_by_default() {
         val timeText = "time"
 
         rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText(
-                    timeSource =
-                        object : TimeSource {
-                            @Composable override fun currentTime(): String = timeText
-                        },
-                )
-            }
+            TimeText(
+                timeSource =
+                    object : TimeSource {
+                        @Composable override fun currentTime(): String = timeText
+                    },
+            )
         }
 
         // Note that onNodeWithText doesn't work for curved text, so only testing for non-round.
-        rule.onNodeWithText(timeText).assertIsDisplayed()
+        rule.onNodeWithContentDescription(timeText).assertIsDisplayed()
     }
 
     @Test
-    fun updates_clock_when_source_changes_on_non_round_device() {
+    fun updates_clock_when_source_changes() {
         val timeState = mutableStateOf("Unchanged")
 
         rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText(
-                    modifier = Modifier.testTag(TEST_TAG),
-                    timeSource =
-                        object : TimeSource {
-                            @Composable override fun currentTime(): String = timeState.value
-                        },
-                ) {
-                    time()
-                }
-            }
+            TimeText(
+                modifier = Modifier.testTag(TEST_TAG),
+                timeSource =
+                    object : TimeSource {
+                        @Composable override fun currentTime(): String = timeState.value
+                    },
+            )
         }
         timeState.value = "Changed"
-        rule.onNodeWithText("Changed").assertIsDisplayed()
-    }
-
-    @Test
-    fun updates_clock_when_source_changes_on_round_device() {
-        val timeState = mutableStateOf("Unchanged")
-
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(true)) {
-                TimeText(
-                    modifier = Modifier.testTag(TEST_TAG),
-                    timeSource =
-                        object : TimeSource {
-                            @Composable override fun currentTime(): String = timeState.value
-                        },
-                ) {
-                    time()
-                }
-            }
-        }
-        timeState.value = "Changed"
-        rule.waitForIdle()
         rule.onNodeWithContentDescription("Changed").assertIsDisplayed()
     }
 
     @Test
-    fun checks_status_displayed_on_non_round_device() {
+    fun checks_status_displayed() {
         val statusText = "Status"
 
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText {
-                    text(statusText)
-                    separator()
-                    time()
-                }
-            }
-        }
-
-        rule.onNodeWithText(statusText).assertIsDisplayed()
-    }
-
-    @Test
-    fun checks_status_displayed_on_round_device() {
-        val statusText = "Status"
-
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(true)) {
-                TimeText {
-                    text(statusText)
-                    separator()
-                    time()
-                }
+        rule.setContentWithTheme() {
+            TimeText { time ->
+                curvedText(statusText)
+                timeTextSeparator()
+                curvedText(time)
             }
         }
 
@@ -149,54 +95,26 @@
     }
 
     @Test
-    fun checks_separator_displayed_on_non_round_device() {
+    fun checks_separator_displayed() {
         val statusText = "Status"
         val separatorText = "·"
 
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText {
-                    text(statusText)
-                    separator()
-                    time()
-                }
-            }
-        }
-
-        rule.onNodeWithText(separatorText).assertIsDisplayed()
-    }
-
-    @Test
-    fun checks_separator_displayed_on_round_device() {
-        val statusText = "Status"
-        val separatorText = "·"
-
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(true)) {
-                TimeText {
-                    text(statusText)
-                    separator()
-                    time()
-                }
-            }
-        }
+        rule.setContentWithTheme { BasicTimeTextWithStatus(statusText) }
 
         rule.onNodeWithContentDescription(separatorText).assertIsDisplayed()
     }
 
     @Test
-    fun checks_composable_displayed_on_non_round_device() {
+    fun checks_composable_displayed() {
         rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText {
-                    time()
-                    separator()
-                    composable {
-                        Text(
-                            modifier = Modifier.testTag(TEST_TAG),
-                            text = "Compose",
-                        )
-                    }
+            TimeText { time ->
+                curvedText(time)
+                timeTextSeparator()
+                curvedComposable {
+                    Text(
+                        modifier = Modifier.testTag(TEST_TAG),
+                        text = "Compose",
+                    )
                 }
             }
         }
@@ -205,178 +123,6 @@
     }
 
     @Test
-    fun checks_composable_displayed_on_round_device() {
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(true)) {
-                TimeText {
-                    time()
-                    separator()
-                    composable {
-                        Text(
-                            modifier = Modifier.testTag(TEST_TAG),
-                            text = "Compose",
-                        )
-                    }
-                }
-            }
-        }
-
-        rule.onNodeWithTag(TEST_TAG).assertIsDisplayed()
-    }
-
-    @Test
-    fun changes_timeTextStyle_on_non_round_device() {
-        val timeText = "testTime"
-
-        val testTextStyle =
-            TextStyle(color = Color.Green, background = Color.Black, fontSize = 20.sp)
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText(
-                    timeSource =
-                        object : TimeSource {
-                            @Composable override fun currentTime(): String = timeText
-                        },
-                    timeTextStyle = testTextStyle
-                ) {
-                    time()
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(timeText)
-        Assert.assertEquals(testTextStyle.color, actualStyle.color)
-        Assert.assertEquals(testTextStyle.background, actualStyle.background)
-        Assert.assertEquals(testTextStyle.fontSize, actualStyle.fontSize)
-    }
-
-    @Test
-    fun changes_material_theme_on_non_round_device_except_color() {
-        val timeText = "testTime"
-
-        val testTextStyle =
-            TextStyle(
-                color = Color.Green,
-                background = Color.Black,
-                fontStyle = FontStyle.Italic,
-                fontSize = 25.sp,
-                fontFamily = FontFamily.SansSerif
-            )
-        rule.setContent {
-            MaterialTheme(typography = MaterialTheme.typography.copy(arcMedium = testTextStyle)) {
-                DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                    TimeText(
-                        timeSource =
-                            object : TimeSource {
-                                @Composable override fun currentTime(): String = timeText
-                            },
-                    ) {
-                        time()
-                    }
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(timeText)
-        Assert.assertEquals(testTextStyle.background, actualStyle.background)
-        Assert.assertEquals(testTextStyle.fontSize, actualStyle.fontSize)
-        Assert.assertEquals(testTextStyle.fontStyle, actualStyle.fontStyle)
-        Assert.assertEquals(testTextStyle.fontFamily, actualStyle.fontFamily)
-        Assert.assertNotEquals(testTextStyle.color, actualStyle.color)
-    }
-
-    @Test
-    fun color_remains_onBackground_when_material_theme_changed_on_non_round_device() {
-        val timeText = "testTime"
-        var onBackgroundColor = Color.Unspecified
-
-        val testTextStyle =
-            TextStyle(
-                color = Color.Green,
-                background = Color.Black,
-                fontStyle = FontStyle.Italic,
-                fontSize = 25.sp,
-                fontFamily = FontFamily.SansSerif
-            )
-        rule.setContent {
-            MaterialTheme(typography = MaterialTheme.typography.copy(labelSmall = testTextStyle)) {
-                onBackgroundColor = MaterialTheme.colorScheme.onBackground
-                DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                    TimeText(
-                        timeSource =
-                            object : TimeSource {
-                                @Composable override fun currentTime(): String = timeText
-                            },
-                    ) {
-                        time()
-                    }
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(timeText)
-        Assert.assertEquals(onBackgroundColor, actualStyle.color)
-    }
-
-    @Test
-    fun has_correct_default_leading_text_color_on_non_round_device() {
-        val leadingText = "leadingText"
-        var primaryColor = Color.Unspecified
-
-        rule.setContentWithTheme {
-            primaryColor = MaterialTheme.colorScheme.primary
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText {
-                    text(leadingText)
-                    separator()
-                    time()
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(leadingText)
-        Assert.assertEquals(primaryColor, actualStyle.color)
-    }
-
-    @Test
-    fun supports_custom_leading_text_color_on_non_round_device() {
-        val leadingText = "leadingText"
-        val customColor = Color.Green
-
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText(
-                    contentColor = customColor,
-                ) {
-                    text(leadingText)
-                    separator()
-                    time()
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(leadingText)
-        Assert.assertEquals(customColor, actualStyle.color)
-    }
-
-    @Test
-    fun supports_custom_text_style_on_non_round_device() {
-        val leadingText = "leadingText"
-
-        val timeTextStyle = TextStyle(background = Color.Blue, fontSize = 14.sp)
-        val contentTextStyle =
-            TextStyle(color = Color.Green, background = Color.Black, fontSize = 20.sp)
-        rule.setContentWithTheme {
-            DeviceConfigurationOverride(DeviceConfigurationOverride.RoundScreen(false)) {
-                TimeText(contentColor = Color.Red, timeTextStyle = timeTextStyle) {
-                    text(leadingText, contentTextStyle)
-                    separator()
-                    time()
-                }
-            }
-        }
-        val actualStyle = rule.textStyleOf(leadingText)
-        Assert.assertEquals(contentTextStyle.color, actualStyle.color)
-        Assert.assertEquals(contentTextStyle.background, actualStyle.background)
-        Assert.assertEquals(contentTextStyle.fontSize, actualStyle.fontSize)
-    }
-
-    @Test
     fun formats_current_time() {
         val currentTimeInMillis = 1631544258000L // 2021-09-13 14:44:18
         val format = "HH:mm:ss"
@@ -418,4 +164,13 @@
         }
         Assert.assertEquals(expectedTime, actualTime)
     }
+
+    @Composable
+    private fun BasicTimeTextWithStatus(statusText: String) {
+        TimeText { time ->
+            curvedText(statusText)
+            timeTextSeparator()
+            curvedText(time)
+        }
+    }
 }
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AppScaffold.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AppScaffold.kt
index edffe7e..51fc42b 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AppScaffold.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/AppScaffold.kt
@@ -46,7 +46,7 @@
 @Composable
 public fun AppScaffold(
     modifier: Modifier = Modifier,
-    timeText: @Composable () -> Unit = { TimeText { time() } },
+    timeText: @Composable () -> Unit = { TimeText() },
     content: @Composable BoxScope.() -> Unit,
 ) {
     CompositionLocalProvider(
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimeText.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimeText.kt
index f95bd3c..351a47c 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimeText.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/TimeText.kt
@@ -22,17 +22,8 @@
 import android.content.IntentFilter
 import android.text.format.DateFormat
 import androidx.annotation.VisibleForTesting
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
@@ -42,17 +33,14 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.StrokeCap
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastForEach
 import androidx.wear.compose.foundation.ArcPaddingValues
 import androidx.wear.compose.foundation.CurvedAlignment
 import androidx.wear.compose.foundation.CurvedDirection
@@ -61,35 +49,29 @@
 import androidx.wear.compose.foundation.CurvedScope
 import androidx.wear.compose.foundation.CurvedTextStyle
 import androidx.wear.compose.foundation.background
-import androidx.wear.compose.foundation.curvedComposable
+import androidx.wear.compose.foundation.basicCurvedText
 import androidx.wear.compose.foundation.curvedRow
 import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.foundation.sizeIn
-import androidx.wear.compose.foundation.weight
-import androidx.wear.compose.material3.TimeTextDefaults.CurvedTextSeparator
-import androidx.wear.compose.material3.TimeTextDefaults.TextSeparator
 import androidx.wear.compose.material3.TimeTextDefaults.timeFormat
+import androidx.wear.compose.material3.TimeTextDefaults.timeTextStyle
 import androidx.wear.compose.materialcore.currentTimeMillis
 import androidx.wear.compose.materialcore.is24HourFormat
-import androidx.wear.compose.materialcore.isRoundDevice
 import java.util.Calendar
 import java.util.Locale
 
 /**
- * Layout to show the current time and a label at the top of the screen. If device has a round
- * screen, then the time will be curved along the top edge of the screen, if rectangular - then the
- * text and the time will be straight.
+ * Layout to show the current time and a label, they will be drawn in a curve, following the top
+ * edge of the screen.
  *
  * Note that Wear Material UX guidance recommends that time text should not be larger than
- * [TimeTextDefaults.MaxSweepAngle] of the screen edge on round devices, which is enforced by
- * default. It is recommended that additional content, if any, is limited to short status messages
- * before the [TimeTextScope.time] using the MaterialTheme.colorScheme.primary color.
+ * [TimeTextDefaults.MaxSweepAngle] of the screen edge, which is enforced by default. It is
+ * recommended that additional content, if any, is limited to short status messages before the time
+ * using the MaterialTheme.colorScheme.primary color.
  *
  * For more information, see the
  * [Curved Text](https://developer.android.com/training/wearables/components/curved-text) guide.
  *
- * Different components of [TimeText] can be added through methods of [TimeTextScope].
- *
  * A simple [TimeText] which shows the current time:
  *
  * @sample androidx.wear.compose.material3.samples.TimeTextClockOnly
@@ -97,15 +79,19 @@
  * A [TimeText] with a short app status message shown:
  *
  * @sample androidx.wear.compose.material3.samples.TimeTextWithStatus
+ *
+ * A [TimeText] with a long status message, that needs ellipsizing:
+ *
+ * @sample androidx.wear.compose.material3.samples.TimeTextWithStatusEllipsized
  * @param modifier The modifier to be applied to the component.
  * @param curvedModifier The [CurvedModifier] used to restrict the arc in which [TimeText] is drawn.
  * @param maxSweepAngle The default maximum sweep angle in degrees.
  * @param timeSource [TimeSource] which retrieves the current time and formats it.
- * @param timeTextStyle [TextStyle] for the time text itself.
- * @param contentColor [Color] of content of displayed through [TimeTextScope.text] and
- *   [TimeTextScope.composable].
  * @param contentPadding The spacing values between the container and the content.
- * @param content The content of the [TimeText] - displays the current time by default.
+ * @param content The content of the [TimeText] - displays the current time by default. This lambda
+ *   receives the current time as a String and should display it using curvedText. Note that if long
+ *   curved text is included here, it should specify [CurvedModifier.weight] on it so that the space
+ *   available is suitably allocated.
  */
 @Composable
 public fun TimeText(
@@ -113,91 +99,31 @@
     curvedModifier: CurvedModifier = CurvedModifier,
     maxSweepAngle: Float = TimeTextDefaults.MaxSweepAngle,
     timeSource: TimeSource = TimeTextDefaults.rememberTimeSource(timeFormat()),
-    timeTextStyle: TextStyle = TimeTextDefaults.timeTextStyle(),
-    contentColor: Color = MaterialTheme.colorScheme.primary,
     contentPadding: PaddingValues = TimeTextDefaults.ContentPadding,
-    content: TimeTextScope.() -> Unit = { time() }
+    content: CurvedScope.(String) -> Unit = { time -> timeTextCurvedText(time) }
 ) {
-    val timeText = timeSource.currentTime()
+    val currentTime = timeSource.currentTime()
     val backgroundColor = CurvedTextDefaults.backgroundColor()
 
-    if (isRoundDevice()) {
-        CurvedLayout(modifier = modifier) {
-            curvedRow(
-                modifier =
-                    curvedModifier
-                        .sizeIn(maxSweepDegrees = maxSweepAngle)
-                        .padding(contentPadding.toArcPadding())
-                        .background(backgroundColor, StrokeCap.Round),
-                radialAlignment = CurvedAlignment.Radial.Center
-            ) {
-                CurvedTimeTextScope(timeText, timeTextStyle, maxSweepAngle, contentColor).apply {
-                    content()
-                    Show()
-                }
-            }
-        }
-    } else {
-        Box(modifier.fillMaxSize()) {
-            Row(
-                modifier =
-                    Modifier.align(Alignment.TopCenter)
-                        .background(backgroundColor, CircleShape)
-                        .padding(contentPadding),
-                verticalAlignment = Alignment.CenterVertically,
-                horizontalArrangement = Arrangement.Center
-            ) {
-                LinearTimeTextScope(timeText, timeTextStyle, contentColor).apply {
-                    content()
-                    Show()
-                }
-            }
+    CurvedLayout(modifier = modifier) {
+        curvedRow(
+            modifier =
+                curvedModifier
+                    .sizeIn(maxSweepDegrees = maxSweepAngle)
+                    .padding(contentPadding.toArcPadding())
+                    .background(backgroundColor, StrokeCap.Round),
+            radialAlignment = CurvedAlignment.Radial.Center
+        ) {
+            content(currentTime)
         }
     }
 }
 
-/** Receiver scope which is used by [TimeText]. */
-public sealed class TimeTextScope {
-    /**
-     * Adds a composable [Text] for non-round devices and [curvedText] for round devices to
-     * [TimeText] content. Typically used to add a short status message ahead of the time text.
-     *
-     * @param text The text to display.
-     * @param style configuration for the [text] such as color, font etc.
-     * @param weight Size the text's width proportional to its weight relative to other weighted
-     *   sibling elements in the TimeText. Specify NaN to make this text not have a weight
-     *   specified. The default value, [TimeTextDefaults.AutoTextWeight], makes this text have
-     *   weight 1f if it's the only one, and not have weight if there are two or more.
-     */
-    public abstract fun text(
-        text: String,
-        style: TextStyle? = null,
-        weight: Float = TimeTextDefaults.AutoTextWeight
-    )
-
-    /** Adds a text displaying current time. */
-    public abstract fun time()
-
-    /**
-     * Adds a separator in [TimeText].
-     *
-     * @param style configuration for the [separator] such as color, font etc.
-     */
-    public abstract fun separator(style: TextStyle? = null)
-
-    /**
-     * Adds a composable in content of [TimeText]. This can be used to display non-text information
-     * such as an icon.
-     *
-     * @param content Slot for the [composable] to be displayed.
-     */
-    public abstract fun composable(content: @Composable () -> Unit)
-}
-
 /** Contains the default values used by [TimeText]. */
 public object TimeTextDefaults {
     /** The default padding from the edge of the screen. */
     private val Padding = PaddingDefaults.edgePadding
+
     /** Default format for 24h clock. */
     public const val TimeFormat24Hours: String = "HH:mm"
 
@@ -228,8 +154,8 @@
     }
 
     /**
-     * Creates a [TextStyle] with default parameters used for showing time on square screens. By
-     * default a copy of MaterialTheme.typography.arcMedium style is created.
+     * Creates a [CurvedTextStyle] with default parameters used for showing time. By default a copy
+     * of MaterialTheme.typography.arcMedium style is created.
      *
      * @param background The background color.
      * @param color The main color.
@@ -240,9 +166,11 @@
         background: Color = Color.Unspecified,
         color: Color = MaterialTheme.colorScheme.onBackground,
         fontSize: TextUnit = TextUnit.Unspecified,
-    ): TextStyle =
-        MaterialTheme.typography.arcMedium +
-            TextStyle(color = color, background = background, fontSize = fontSize)
+    ): CurvedTextStyle =
+        CurvedTextStyle(
+            MaterialTheme.typography.arcMedium +
+                TextStyle(color = color, background = background, fontSize = fontSize)
+        )
 
     /**
      * Creates a default implementation of [TimeSource] and remembers it. Once the system time
@@ -260,48 +188,37 @@
     @Composable
     public fun rememberTimeSource(timeFormat: String): TimeSource =
         remember(timeFormat) { DefaultTimeSource(timeFormat) }
+}
 
-    /**
-     * A default implementation of Separator shown between any text/composable and the time on
-     * non-round screens.
-     *
-     * @param modifier A default modifier for the separator.
-     * @param textStyle A [TextStyle] for the separator.
-     * @param contentPadding The spacing values between the container and the separator.
-     */
-    @Composable
-    internal fun TextSeparator(
-        modifier: Modifier = Modifier,
-        textStyle: TextStyle = timeTextStyle(),
-        contentPadding: PaddingValues = PaddingValues(horizontal = 4.dp)
+/**
+ * Default curved text to use in a [TimeText], for displaying the time
+ *
+ * @param time The time to display.
+ * @param style A [CurvedTextStyle] to override the style used.
+ */
+public fun CurvedScope.timeTextCurvedText(time: String, style: CurvedTextStyle? = null) {
+    basicCurvedText(
+        time,
     ) {
-        Text(text = "·", style = textStyle, modifier = modifier.padding(contentPadding))
+        style?.let { timeTextStyle() + it } ?: timeTextStyle()
     }
+}
 
-    /**
-     * A default implementation of Separator shown between any text/composable and the time on round
-     * screens.
-     *
-     * @param curvedTextStyle A [CurvedTextStyle] for the separator.
-     * @param contentArcPadding [ArcPaddingValues] for the separator text.
-     */
-    internal fun CurvedScope.CurvedTextSeparator(
-        curvedTextStyle: CurvedTextStyle? = null,
-        contentArcPadding: ArcPaddingValues = ArcPaddingValues(angular = 4.dp)
-    ) {
-        curvedText(
-            text = "·",
-            style = curvedTextStyle,
-            modifier = CurvedModifier.padding(contentArcPadding)
-        )
-    }
-
-    /**
-     * Weight value used to specify that the value is automatic. It will be 1f when there is one
-     * text, and no weight will be used if there are 2 or more texts. For the 2+ texts case, usually
-     * one of them should have weight manually specified to ensure its properly cut and ellipsized.
-     */
-    public val AutoTextWeight: Float = -1f
+/**
+ * A default implementation of Separator, to be shown between any text/composable and the time.
+ *
+ * @param curvedTextStyle A [CurvedTextStyle] for the separator.
+ * @param contentArcPadding [ArcPaddingValues] for the separator text.
+ */
+public fun CurvedScope.timeTextSeparator(
+    curvedTextStyle: CurvedTextStyle? = null,
+    contentArcPadding: ArcPaddingValues = ArcPaddingValues(angular = 4.dp)
+) {
+    curvedText(
+        text = "·",
+        style = curvedTextStyle,
+        modifier = CurvedModifier.padding(contentArcPadding)
+    )
 }
 
 public interface TimeSource {
@@ -314,122 +231,6 @@
     @Composable public fun currentTime(): String
 }
 
-/** Implementation of [TimeTextScope] for round devices. */
-internal class CurvedTimeTextScope(
-    private val timeText: String,
-    private val timeTextStyle: TextStyle,
-    private val maxSweepAngle: Float,
-    contentColor: Color,
-) : TimeTextScope() {
-    private var textCount = 0
-    private val pending = mutableListOf<CurvedScope.() -> Unit>()
-    private val contentTextStyle = timeTextStyle.merge(contentColor)
-
-    override fun text(text: String, style: TextStyle?, weight: Float) {
-        textCount++
-        pending.add {
-            curvedText(
-                text = text,
-                overflow = TextOverflow.Ellipsis,
-                maxSweepAngle = maxSweepAngle,
-                style = CurvedTextStyle(style = contentTextStyle.merge(style)),
-                modifier =
-                    if (weight.isValidWeight()) CurvedModifier.weight(weight)
-                    // Note that we are creating a lambda here, but textCount is actually read
-                    // later, during the call to Show, when the pending list is fully constructed.
-                    else if (weight == TimeTextDefaults.AutoTextWeight && textCount <= 1)
-                        CurvedModifier.weight(1f)
-                    else CurvedModifier
-            )
-        }
-    }
-
-    override fun time() {
-        pending.add {
-            curvedText(
-                timeText,
-                maxSweepAngle = maxSweepAngle,
-                style = CurvedTextStyle(timeTextStyle)
-            )
-        }
-    }
-
-    override fun separator(style: TextStyle?) {
-        pending.add { CurvedTextSeparator(CurvedTextStyle(style = timeTextStyle.merge(style))) }
-    }
-
-    override fun composable(content: @Composable () -> Unit) {
-        pending.add {
-            curvedComposable {
-                CompositionLocalProvider(
-                    LocalContentColor provides contentTextStyle.color,
-                    LocalTextStyle provides contentTextStyle,
-                    content = content
-                )
-            }
-        }
-    }
-
-    fun CurvedScope.Show() {
-        pending.fastForEach { it() }
-    }
-}
-
-/** Implementation of [TimeTextScope] for non-round devices. */
-internal class LinearTimeTextScope(
-    private val timeText: String,
-    private val timeTextStyle: TextStyle,
-    contentColor: Color,
-) : TimeTextScope() {
-    private var textCount = 0
-    private val pending = mutableListOf<@Composable RowScope.() -> Unit>()
-    private val contentTextStyle = timeTextStyle.merge(contentColor)
-
-    override fun text(text: String, style: TextStyle?, weight: Float) {
-        textCount++
-        pending.add {
-            Text(
-                text = text,
-                maxLines = 1,
-                overflow = TextOverflow.Ellipsis,
-                style = contentTextStyle.merge(style),
-                modifier =
-                    if (weight.isValidWeight()) Modifier.weight(weight, fill = false)
-                    // Note that we are creating a lambda here, but textCount is actually read
-                    // later, during the call to Show, when the pending list is fully constructed.
-                    else if (weight == TimeTextDefaults.AutoTextWeight && textCount <= 1)
-                        Modifier.weight(1f, fill = false)
-                    else Modifier
-            )
-        }
-    }
-
-    override fun time() {
-        pending.add { Text(timeText, style = timeTextStyle) }
-    }
-
-    override fun separator(style: TextStyle?) {
-        pending.add { TextSeparator(textStyle = timeTextStyle.merge(style)) }
-    }
-
-    override fun composable(content: @Composable () -> Unit) {
-        pending.add {
-            CompositionLocalProvider(
-                LocalContentColor provides contentTextStyle.color,
-                LocalTextStyle provides contentTextStyle,
-                content = content
-            )
-        }
-    }
-
-    @Composable
-    fun RowScope.Show() {
-        pending.fastForEach { it() }
-    }
-}
-
-private fun Float.isValidWeight() = !isNaN() && this > 0f
-
 internal class DefaultTimeSource(timeFormat: String) : TimeSource {
     private val _timeFormat = timeFormat
 
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..685cf6d 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
@@ -109,7 +109,7 @@
         @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() } }
+                val timeText = @Composable { androidx.wear.compose.material3.TimeText() }
                 androidx.wear.compose.material3.ScreenScaffold(
                     scrollState = state,
                     timeText = remember { timeText },
diff --git a/wear/compose/integration-tests/navigation/build.gradle b/wear/compose/integration-tests/navigation/build.gradle
index 68bb715..3d052ae 100644
--- a/wear/compose/integration-tests/navigation/build.gradle
+++ b/wear/compose/integration-tests/navigation/build.gradle
@@ -43,6 +43,7 @@
 dependencies {
 
     implementation("androidx.activity:activity-compose:1.5.1")
+    implementation("androidx.compose.material:material-icons-core:1.6.7")
     implementation(project(":compose:ui:ui"))
     implementation(project(":compose:integration-tests:demos:common"))
     implementation(project(":compose:foundation:foundation"))
diff --git a/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/MainActivity.kt b/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/MainActivity.kt
index 5e56425..2df366b 100644
--- a/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/MainActivity.kt
+++ b/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/MainActivity.kt
@@ -27,14 +27,18 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import androidx.wear.compose.foundation.edgeSwipeToDismiss
+import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
+import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
 import androidx.wear.compose.foundation.pager.rememberPagerState
 import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
 import androidx.wear.compose.material.CompactChip
+import androidx.wear.compose.material.ListHeader
 import androidx.wear.compose.material.MaterialTheme
 import androidx.wear.compose.material.Text
 import androidx.wear.compose.material3.AppScaffold
@@ -52,6 +56,7 @@
 
         setContent(parent = null) {
             MaterialTheme {
+                val transformingLazyColumnState = rememberTransformingLazyColumnState()
                 val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
                 val navController = rememberSwipeDismissableNavController()
                 SwipeDismissableNavHost(
@@ -60,26 +65,45 @@
                     startDestination = START
                 ) {
                     composable(START) {
-                        Column(
-                            horizontalAlignment = Alignment.CenterHorizontally,
-                            verticalArrangement = Arrangement.Center,
-                            modifier = Modifier.fillMaxSize(),
+                        TransformingLazyColumn(
+                            state = transformingLazyColumnState,
+                            modifier = Modifier.padding(horizontal = 10.dp)
                         ) {
-                            Text(text = "Screen 1", color = MaterialTheme.colors.onSurface)
-                            CompactChip(
-                                onClick = { navController.navigate(SCREEN2) },
-                                label = { Text("Next screen") },
-                            )
-                            Spacer(modifier = Modifier.fillMaxWidth().height(4.dp))
-                            CompactChip(
-                                onClick = { navController.navigate(EDGE_SWIPE_SCREEN) },
-                                label = { Text("Screen with edge swipe") },
-                            )
-                            Spacer(modifier = Modifier.fillMaxWidth().height(4.dp))
-                            CompactChip(
-                                onClick = { navController.navigate(PAGER_SCAFFOLD_SCREEN) },
-                                label = { Text("Screen with PagerScaffold") },
-                            )
+                            item {
+                                ListHeader {
+                                    Text(text = "Screen 1", color = MaterialTheme.colors.onSurface)
+                                }
+                            }
+                            item {
+                                CompactChip(
+                                    onClick = { navController.navigate(SCREEN2) },
+                                    label = { Text("Next screen") },
+                                )
+                            }
+                            item {
+                                CompactChip(
+                                    onClick = { navController.navigate(EDGE_SWIPE_SCREEN) },
+                                    label = { Text("Screen with edge swipe") },
+                                )
+                            }
+                            item {
+                                CompactChip(
+                                    onClick = { navController.navigate(PAGER_SCAFFOLD_SCREEN) },
+                                    label = { Text("Screen with PagerScaffold") },
+                                )
+                            }
+                            item {
+                                CompactChip(
+                                    onClick = { navController.navigate(S2R_STANDARD_SCREEN) },
+                                    label = { Text("S2R - Standard") },
+                                )
+                            }
+                            item {
+                                CompactChip(
+                                    onClick = { navController.navigate(S2R_DUAL_DIRECTION_SCREEN) },
+                                    label = { Text("S2R - Dual Direction") },
+                                )
+                            }
                         }
                     }
                     composable(SCREEN2) {
@@ -152,6 +176,12 @@
                             }
                         }
                     }
+
+                    composable(S2R_STANDARD_SCREEN) { SwipeToRevealSingleButtonWithAnchoring() }
+
+                    composable(S2R_DUAL_DIRECTION_SCREEN) {
+                        SwipeToRevealBothDirectionsNonAnchoring()
+                    }
                 }
             }
         }
@@ -163,3 +193,5 @@
 private const val SCREEN3 = "screen3"
 private const val EDGE_SWIPE_SCREEN = "edge_swipe_screen"
 private const val PAGER_SCAFFOLD_SCREEN = "pager_scaffold_screen"
+private const val S2R_STANDARD_SCREEN = "s2r_standard_screen"
+private const val S2R_DUAL_DIRECTION_SCREEN = "s2r_dual_direction_screen"
diff --git a/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/SwipeToRevealScreen.kt b/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/SwipeToRevealScreen.kt
new file mode 100644
index 0000000..0b72ca6
--- /dev/null
+++ b/wear/compose/integration-tests/navigation/src/main/java/androidx/wear/compose/integration/navigation/SwipeToRevealScreen.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.integration.navigation
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.SwipeDirection
+import androidx.wear.compose.material3.Button
+import androidx.wear.compose.material3.Icon
+import androidx.wear.compose.material3.SwipeToReveal
+import androidx.wear.compose.material3.SwipeToRevealDefaults
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.rememberRevealState
+
+@Composable
+fun SwipeToRevealSingleButtonWithAnchoring() {
+    Box(
+        modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp),
+        contentAlignment = Alignment.Center
+    ) {
+        SwipeToReveal(
+            revealState =
+                rememberRevealState(
+                    swipeDirection = SwipeDirection.RightToLeft,
+                    anchorWidth = SwipeToRevealDefaults.SingleActionAnchorWidth,
+                ),
+            actions = {
+                primaryAction(
+                    onClick = { /* This block is called when the primary action is executed. */ },
+                    icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
+                    text = { Text("Delete") },
+                    label = "Delete"
+                )
+                undoPrimaryAction(
+                    onClick = { /* This block is called when the undo primary action is executed. */
+                    },
+                    text = { Text("Undo Delete") },
+                )
+            }
+        ) {
+            Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
+                Text("This Button has only one action", modifier = Modifier.fillMaxWidth())
+            }
+        }
+    }
+}
+
+@Composable
+fun SwipeToRevealBothDirectionsNonAnchoring() {
+    Box(
+        modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp),
+        contentAlignment = Alignment.Center
+    ) {
+        SwipeToReveal(
+            revealState =
+                rememberRevealState(
+                    swipeDirection = SwipeDirection.Both,
+                    useAnchoredActions = false,
+                ),
+            actions = {
+                primaryAction(
+                    onClick = { /* This block is called when the primary action is executed. */ },
+                    icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
+                    text = { Text("Delete") },
+                    label = "Delete"
+                )
+                undoPrimaryAction(
+                    onClick = { /* This block is called when the undo primary action is executed. */
+                    },
+                    text = { Text("Undo Delete") },
+                )
+            }
+        ) {
+            Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
+                Text("This Button has only one action", modifier = Modifier.fillMaxWidth())
+            }
+        }
+    }
+}
diff --git a/wear/protolayout/protolayout-material3/api/current.txt b/wear/protolayout/protolayout-material3/api/current.txt
index eae2d58..fb54399 100644
--- a/wear/protolayout/protolayout-material3/api/current.txt
+++ b/wear/protolayout/protolayout-material3/api/current.txt
@@ -11,6 +11,15 @@
     method public androidx.wear.protolayout.material3.AppCardStyle smallAppCardStyle();
   }
 
+  public final class AvatarButtonStyle {
+    field public static final androidx.wear.protolayout.material3.AvatarButtonStyle.Companion Companion;
+  }
+
+  public static final class AvatarButtonStyle.Companion {
+    method public androidx.wear.protolayout.material3.AvatarButtonStyle defaultAvatarButtonStyle();
+    method public androidx.wear.protolayout.material3.AvatarButtonStyle largeAvatarButtonStyle();
+  }
+
   public final class ButtonColors {
     ctor public ButtonColors();
     ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor containerColor, optional androidx.wear.protolayout.types.LayoutColor iconColor, optional androidx.wear.protolayout.types.LayoutColor labelColor, optional androidx.wear.protolayout.types.LayoutColor secondaryLabelColor);
@@ -48,6 +57,7 @@
   }
 
   public final class ButtonKt {
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement avatarButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> avatarContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional androidx.wear.protolayout.material3.AvatarButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.ButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement compactButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional androidx.wear.protolayout.material3.IconButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
@@ -248,7 +258,24 @@
   }
 
   public final class PrimaryLayoutKt {
-    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement primaryLayout(androidx.wear.protolayout.material3.MaterialScope, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> mainSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? titleSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? bottomSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelForBottomSlot, optional androidx.wear.protolayout.ModifiersBuilders.Clickable? onClick);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement primaryLayout(androidx.wear.protolayout.material3.MaterialScope, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> mainSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? titleSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? bottomSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelForBottomSlot, optional androidx.wear.protolayout.ModifiersBuilders.Clickable? onClick, optional androidx.wear.protolayout.material3.PrimaryLayoutMargins margins);
+  }
+
+  public abstract class PrimaryLayoutMargins {
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion Companion;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins DEFAULT_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MAX_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MID_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MIN_PRIMARY_LAYOUT_MARGIN;
+  }
+
+  public static final class PrimaryLayoutMargins.Companion {
+    method public androidx.wear.protolayout.material3.PrimaryLayoutMargins customizedPrimaryLayoutMargin(@FloatRange(from=0.0, to=1.0) float start, @FloatRange(from=0.0, to=1.0) float end);
+    method public androidx.wear.protolayout.material3.PrimaryLayoutMargins customizedPrimaryLayoutMargin(@FloatRange(from=0.0, to=1.0) float start, @FloatRange(from=0.0, to=1.0) float end, @FloatRange(from=0.0, to=1.0) float bottom);
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins DEFAULT_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MAX_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MID_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MIN_PRIMARY_LAYOUT_MARGIN;
   }
 
   public final class ProgressIndicatorColors {
diff --git a/wear/protolayout/protolayout-material3/api/restricted_current.txt b/wear/protolayout/protolayout-material3/api/restricted_current.txt
index eae2d58..fb54399 100644
--- a/wear/protolayout/protolayout-material3/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material3/api/restricted_current.txt
@@ -11,6 +11,15 @@
     method public androidx.wear.protolayout.material3.AppCardStyle smallAppCardStyle();
   }
 
+  public final class AvatarButtonStyle {
+    field public static final androidx.wear.protolayout.material3.AvatarButtonStyle.Companion Companion;
+  }
+
+  public static final class AvatarButtonStyle.Companion {
+    method public androidx.wear.protolayout.material3.AvatarButtonStyle defaultAvatarButtonStyle();
+    method public androidx.wear.protolayout.material3.AvatarButtonStyle largeAvatarButtonStyle();
+  }
+
   public final class ButtonColors {
     ctor public ButtonColors();
     ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor containerColor, optional androidx.wear.protolayout.types.LayoutColor iconColor, optional androidx.wear.protolayout.types.LayoutColor labelColor, optional androidx.wear.protolayout.types.LayoutColor secondaryLabelColor);
@@ -48,6 +57,7 @@
   }
 
   public final class ButtonKt {
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement avatarButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> avatarContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional androidx.wear.protolayout.material3.AvatarButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.ButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement compactButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional androidx.wear.protolayout.material3.IconButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
@@ -248,7 +258,24 @@
   }
 
   public final class PrimaryLayoutKt {
-    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement primaryLayout(androidx.wear.protolayout.material3.MaterialScope, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> mainSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? titleSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? bottomSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelForBottomSlot, optional androidx.wear.protolayout.ModifiersBuilders.Clickable? onClick);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement primaryLayout(androidx.wear.protolayout.material3.MaterialScope, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> mainSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? titleSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? bottomSlot, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? labelForBottomSlot, optional androidx.wear.protolayout.ModifiersBuilders.Clickable? onClick, optional androidx.wear.protolayout.material3.PrimaryLayoutMargins margins);
+  }
+
+  public abstract class PrimaryLayoutMargins {
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion Companion;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins DEFAULT_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MAX_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MID_PRIMARY_LAYOUT_MARGIN;
+    field public static final androidx.wear.protolayout.material3.PrimaryLayoutMargins MIN_PRIMARY_LAYOUT_MARGIN;
+  }
+
+  public static final class PrimaryLayoutMargins.Companion {
+    method public androidx.wear.protolayout.material3.PrimaryLayoutMargins customizedPrimaryLayoutMargin(@FloatRange(from=0.0, to=1.0) float start, @FloatRange(from=0.0, to=1.0) float end);
+    method public androidx.wear.protolayout.material3.PrimaryLayoutMargins customizedPrimaryLayoutMargin(@FloatRange(from=0.0, to=1.0) float start, @FloatRange(from=0.0, to=1.0) float end, @FloatRange(from=0.0, to=1.0) float bottom);
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins DEFAULT_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MAX_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MID_PRIMARY_LAYOUT_MARGIN;
+    property public final androidx.wear.protolayout.material3.PrimaryLayoutMargins MIN_PRIMARY_LAYOUT_MARGIN;
   }
 
   public final class ProgressIndicatorColors {
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
index e5d1f6a..64bd836 100644
--- 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
@@ -38,9 +38,13 @@
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.largeCompactDataCardStyle
 import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.largeGraphicDataCardStyle
+import androidx.wear.protolayout.material3.MaterialScope
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
 import androidx.wear.protolayout.material3.TitleCardStyle.Companion.largeTitleCardStyle
 import androidx.wear.protolayout.material3.Typography
 import androidx.wear.protolayout.material3.appCard
+import androidx.wear.protolayout.material3.avatarButton
+import androidx.wear.protolayout.material3.avatarImage
 import androidx.wear.protolayout.material3.backgroundImage
 import androidx.wear.protolayout.material3.button
 import androidx.wear.protolayout.material3.buttonGroup
@@ -145,7 +149,7 @@
                                 ModifiersBuilders.Modifiers.Builder()
                                     .setBackground(
                                         ModifiersBuilders.Background.Builder()
-                                            .setCorner(shapes.full)
+                                            .setCorner(shapes.small)
                                             .build()
                                     )
                                     .build()
@@ -154,6 +158,8 @@
                     }
                 }
             },
+            // Adjust margins as the corner of the inner content is on the square side.
+            margins = MAX_PRIMARY_LAYOUT_MARGIN,
             bottomSlot = {
                 iconEdgeButton(
                     onClick = clickable,
@@ -464,6 +470,16 @@
     }
 
 @Sampled
+fun MaterialScope.avatarButtonSample() =
+    avatarButton(
+        onClick = clickable(),
+        modifier = LayoutModifier.contentDescription("Pill button"),
+        avatarContent = { avatarImage("id") },
+        labelContent = { text("Primary label".layoutString) },
+        secondaryLabelContent = { text("Secondary label".layoutString) },
+    )
+
+@Sampled
 fun compactButtonsSample(
     context: Context,
     deviceConfiguration: DeviceParameters,
diff --git a/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt b/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
index 4537676..b631b44 100644
--- a/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
+++ b/wear/protolayout/protolayout-material3/src/androidTest/java/androidx/wear/protolayout/material3/TestCasesGenerator.kt
@@ -24,8 +24,10 @@
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.LayoutElementBuilders
 import androidx.wear.protolayout.LayoutElementBuilders.Column
+import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_END
 import androidx.wear.protolayout.expression.VersionBuilders.VersionInfo
 import androidx.wear.protolayout.material3.AppCardStyle.Companion.largeAppCardStyle
+import androidx.wear.protolayout.material3.AvatarButtonStyle.Companion.largeAvatarButtonStyle
 import androidx.wear.protolayout.material3.ButtonDefaults.filledButtonColors
 import androidx.wear.protolayout.material3.ButtonDefaults.filledTonalButtonColors
 import androidx.wear.protolayout.material3.ButtonDefaults.filledVariantButtonColors
@@ -36,10 +38,11 @@
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.smallCompactDataCardStyle
 import androidx.wear.protolayout.material3.IconButtonStyle.Companion.largeIconButtonStyle
 import androidx.wear.protolayout.material3.MaterialGoldenTest.Companion.pxToDp
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MIN_PRIMARY_LAYOUT_MARGIN
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.extraLargeTextButtonStyle
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.largeTextButtonStyle
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.smallTextButtonStyle
-import androidx.wear.protolayout.material3.TitleContentPlacementInDataCard.Companion.Bottom
 import androidx.wear.protolayout.modifiers.LayoutModifier
 import androidx.wear.protolayout.modifiers.clickable
 import androidx.wear.protolayout.modifiers.clip
@@ -135,6 +138,7 @@
                             graphic = { circularProgressIndicator(staticProgress = 0.5F) }
                         )
                     },
+                    margins = MIN_PRIMARY_LAYOUT_MARGIN
                 )
             }
         testCases["primarylayout_edgebuttonfilledvariant_iconoverride_golden$NORMAL_SCALE_SUFFIX"] =
@@ -153,17 +157,9 @@
                                     title = { text("MM".layoutString) },
                                     content = { text("Min".layoutString) },
                                     secondaryIcon = { icon(ICON_ID) },
-                                    shape = shapes.full
-                                )
-                            }
-                            buttonGroupItem {
-                                iconDataCard(
-                                    onClick = clickable,
-                                    modifier = LayoutModifier.contentDescription("Data Card"),
-                                    title = { text("MM".layoutString) },
-                                    content = { text("Min".layoutString) },
-                                    secondaryIcon = { icon(ICON_ID) },
-                                    titleContentPlacement = Bottom
+                                    shape = shapes.none,
+                                    width = expand(),
+                                    height = expand()
                                 )
                             }
                             buttonGroupItem {
@@ -178,11 +174,13 @@
                                             backgroundColor = colorScheme.onSecondary,
                                             titleColor = colorScheme.secondary,
                                             contentColor = colorScheme.secondaryDim
-                                        )
+                                        ),
+                                    shape = shapes.full
                                 )
                             }
                         }
                     },
+                    margins = MAX_PRIMARY_LAYOUT_MARGIN,
                     bottomSlot = {
                         textEdgeButton(
                             onClick = clickable,
@@ -392,6 +390,47 @@
                     },
                 )
             }
+        testCases["primarylayout_nobottomslotnotitle_avatarbuttons_golden$NORMAL_SCALE_SUFFIX"] =
+            materialScope(
+                ApplicationProvider.getApplicationContext(),
+                deviceParameters,
+                allowDynamicTheme = false
+            ) {
+                primaryLayout(
+                    mainSlot = {
+                        Column.Builder()
+                            .setWidth(expand())
+                            .setHeight(expand())
+                            .addContent(
+                                avatarButton(
+                                    onClick = clickable,
+                                    labelContent = { text("Primary label".layoutString) },
+                                    secondaryLabelContent = {
+                                        text("Secondary label".layoutString)
+                                    },
+                                    avatarContent = { avatarImage(IMAGE_ID) },
+                                )
+                            )
+                            .addContent(DEFAULT_SPACER_BETWEEN_BUTTON_GROUPS)
+                            .addContent(
+                                avatarButton(
+                                    onClick = clickable,
+                                    labelContent = {
+                                        text("Primary label overflowing".layoutString)
+                                    },
+                                    secondaryLabelContent = {
+                                        text("Secondary label overflowing".layoutString)
+                                    },
+                                    avatarContent = { avatarImage(IMAGE_ID) },
+                                    height = expand(),
+                                    style = largeAvatarButtonStyle(),
+                                    horizontalAlignment = HORIZONTAL_ALIGN_END
+                                )
+                            )
+                            .build()
+                    },
+                )
+            }
         testCases["primarylayout_oneslotbuttons_golden$NORMAL_SCALE_SUFFIX"] =
             materialScope(
                 ApplicationProvider.getApplicationContext(),
@@ -473,7 +512,10 @@
                 deviceParameters,
                 allowDynamicTheme = false
             ) {
-                primaryLayout(mainSlot = { progressIndicatorGroup() })
+                primaryLayout(
+                    mainSlot = { progressIndicatorGroup() },
+                    margins = MIN_PRIMARY_LAYOUT_MARGIN
+                )
             }
 
         testCases["primarylayout_circularprogressindicators_fallback__golden$NORMAL_SCALE_SUFFIX"] =
@@ -486,6 +528,7 @@
             ) {
                 primaryLayout(
                     mainSlot = { progressIndicatorGroup() },
+                    margins = MIN_PRIMARY_LAYOUT_MARGIN,
                     bottomSlot = {
                         iconEdgeButton(
                             onClick = clickable,
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
index c6d834e..8940585 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
@@ -16,10 +16,12 @@
 
 package androidx.wear.protolayout.material3
 
+import androidx.wear.protolayout.DimensionBuilders
 import androidx.wear.protolayout.DimensionBuilders.ContainerDimension
 import androidx.wear.protolayout.DimensionBuilders.dp
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.DimensionBuilders.weight
+import androidx.wear.protolayout.LayoutElementBuilders
 import androidx.wear.protolayout.LayoutElementBuilders.Box
 import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER
 import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_END
@@ -29,9 +31,11 @@
 import androidx.wear.protolayout.ModifiersBuilders.Clickable
 import androidx.wear.protolayout.ModifiersBuilders.Corner
 import androidx.wear.protolayout.ModifiersBuilders.Padding
+import androidx.wear.protolayout.material3.AvatarButtonStyle.Companion.defaultAvatarButtonStyle
 import androidx.wear.protolayout.material3.ButtonDefaults.DEFAULT_CONTENT_PADDING
 import androidx.wear.protolayout.material3.ButtonDefaults.IMAGE_BUTTON_DEFAULT_SIZE_DP
 import androidx.wear.protolayout.material3.ButtonDefaults.METADATA_TAG_BUTTON
+import androidx.wear.protolayout.material3.ButtonDefaults.buildContentForAvatarButton
 import androidx.wear.protolayout.material3.ButtonDefaults.buildContentForCompactButton
 import androidx.wear.protolayout.material3.ButtonDefaults.buildContentForPillShapeButton
 import androidx.wear.protolayout.material3.ButtonDefaults.filledButtonColors
@@ -42,6 +46,8 @@
 import androidx.wear.protolayout.material3.CompactButtonStyle.COMPACT_BUTTON_ICON_SIZE_SMALL_DP
 import androidx.wear.protolayout.material3.CompactButtonStyle.COMPACT_BUTTON_LABEL_TYPOGRAPHY
 import androidx.wear.protolayout.material3.IconButtonStyle.Companion.defaultIconButtonStyle
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.maxPrimaryLayoutMargins
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.minPrimaryLayoutMargins
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.defaultTextButtonStyle
 import androidx.wear.protolayout.modifiers.LayoutModifier
 import androidx.wear.protolayout.modifiers.background
@@ -62,7 +68,11 @@
  *   the associated action.
  * @param modifier Modifiers to set to this element. It's highly recommended to set a content
  *   description using [contentDescription].
- * @param shape Defines the button's shape, in other words the corner radius for this button.
+ * @param shape Defines the button's shape, in other words the corner radius for this button. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param width The width of this button. It's highly recommended to set this to [expand] or
  *   [weight]
  * @param height The height of this button. It's highly recommended to set this to [expand] or
@@ -82,7 +92,6 @@
  * @sample androidx.wear.protolayout.material3.samples.oneSlotButtonsSample
  */
 // TODO: b/346958146 - Link Button visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.iconButton(
     onClick: Clickable,
     iconContent: (MaterialScope.() -> LayoutElement),
@@ -121,7 +130,11 @@
  *   the associated action.
  * @param modifier Modifiers to set to this element. It's highly recommended to set a content
  *   description using [contentDescription].
- * @param shape Defines the button's shape, in other words the corner radius for this button.
+ * @param shape Defines the button's shape, in other words the corner radius for this button. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param width The width of this button. It's highly recommended to set this to [expand] or
  *   [weight]
  * @param height The height of this button. It's highly recommended to set this to [expand] or
@@ -142,7 +155,6 @@
  * @sample androidx.wear.protolayout.material3.samples.oneSlotButtonsSample
  */
 // TODO: b/346958146 - Link Button visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.textButton(
     onClick: Clickable,
     labelContent: (MaterialScope.() -> LayoutElement),
@@ -186,7 +198,11 @@
  *   recommended to use default styling that is automatically provided by only calling [text].
  * @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.
- * @param shape Defines the button's shape, in other words the corner radius for this button.
+ * @param shape Defines the button's shape, in other words the corner radius for this button. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param width The width of this button. It's highly recommended to set this to [expand] or
  *   [weight]
  * @param height The height of this button. It's highly recommended to set this to [expand] or
@@ -279,6 +295,119 @@
     )
 
 /**
+ * Opinionated ProtoLayout Material3 pill shape avatar button that offers up to three slots to take
+ * content representing vertically stacked label and secondary label, and an image (avatar) next to
+ * it.
+ *
+ * Difference from the [button] is that this one takes an image instead of an icon and spaces the
+ * content proportionally, so that edge of the button nicely hugs the avatar image.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ *   the associated action.
+ * @param labelContent The text slot for content displayed in this button. It is recommended to use
+ *   default styling that is automatically provided by only calling [text].
+ * @param modifier Modifiers to set to this element. It's highly recommended to set a content
+ *   description using [contentDescription].
+ * @param secondaryLabelContent The text slot for content displayed in this button. It is
+ *   recommended to use default styling that is automatically provided by only calling [text].
+ * @param avatarContent The avatar slot for content displayed in this button. It is recommended to
+ *   use default styling that is automatically provided by only calling [avatarImage] with the
+ *   resource ID. Width and height of this element should be set to [expand].
+ * @param shape Defines the button's shape, in other words the corner radius for this button. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
+ * @param height The height of this button. It's highly recommended to set this to [expand] or
+ *   [weight]
+ * @param colors The colors used for this button. If not set, [ButtonDefaults.filledButtonColors]
+ *   will be used as high emphasis button. Other recommended colors are
+ *   [ButtonDefaults.filledTonalButtonColors] and [ButtonDefaults.filledVariantButtonColors]. 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 which provides the attribute values required for constructing this pill
+ *   shape button and its inner content. It also provides default style for the inner content, that
+ *   can be overridden by each content slot.
+ * @param horizontalAlignment The horizontal placement of the [avatarContent]. This should be
+ *   [HORIZONTAL_ALIGN_START] to place the [avatarContent] on the start side of the button, or
+ *   [HORIZONTAL_ALIGN_END] to place in on the end side. [HORIZONTAL_ALIGN_CENTER] will be ignored
+ *   and replaced with [HORIZONTAL_ALIGN_START].
+ * @param contentPadding The inner padding used to prevent inner content from being too close to the
+ *   button's edge. It's highly recommended to keep the default. Only vertical values would be used,
+ *   as horizontally elements are spaced out proportionally to the buttons width.
+ * @sample androidx.wear.protolayout.material3.samples.avatarButtonSample
+ */
+// TODO: b/346958146 - Link Button visuals in DAC
+public fun MaterialScope.avatarButton(
+    onClick: Clickable,
+    labelContent: (MaterialScope.() -> LayoutElement),
+    avatarContent: (MaterialScope.() -> LayoutElement),
+    modifier: LayoutModifier = LayoutModifier,
+    secondaryLabelContent: (MaterialScope.() -> LayoutElement)? = null,
+    height: ContainerDimension = wrapWithMinTapTargetDimension(),
+    shape: Corner = shapes.full,
+    colors: ButtonColors = filledButtonColors(),
+    style: AvatarButtonStyle = defaultAvatarButtonStyle(),
+    @HorizontalAlignment horizontalAlignment: Int = HORIZONTAL_ALIGN_START,
+    contentPadding: Padding = style.innerVerticalPadding
+): LayoutElement =
+    buttonContainer(
+        onClick = onClick,
+        modifier = modifier.background(color = colors.containerColor, corner = shape),
+        width = expand(),
+        height = height,
+        contentPadding = contentPadding,
+        content = {
+            buildContentForAvatarButton(
+                label =
+                    withStyle(
+                            defaultTextElementStyle =
+                                TextElementStyle(
+                                    typography = style.labelTypography,
+                                    color = colors.labelColor,
+                                    multilineAlignment =
+                                        HORIZONTAL_ALIGN_START.horizontalAlignToTextAlign()
+                                )
+                        )
+                        .labelContent(),
+                secondaryLabel =
+                    secondaryLabelContent?.let {
+                        withStyle(
+                                defaultTextElementStyle =
+                                    TextElementStyle(
+                                        typography = style.secondaryLabelTypography,
+                                        color = colors.secondaryLabelColor,
+                                        multilineAlignment =
+                                            HORIZONTAL_ALIGN_START.horizontalAlignToTextAlign()
+                                    )
+                            )
+                            .secondaryLabelContent()
+                    },
+                avatar =
+                    withStyle(
+                            defaultAvatarImageStyle =
+                                AvatarImageStyle(
+                                    width = expand(),
+                                    // We want height to be same as the calculated width
+                                    height =
+                                        DimensionBuilders.ProportionalDimensionProp.Builder()
+                                            .setAspectRatioWidth(1)
+                                            .setAspectRatioHeight(1)
+                                            .build(),
+                                    contentScaleMode = LayoutElementBuilders.CONTENT_SCALE_MODE_FIT
+                                )
+                        )
+                        .avatarContent(),
+                horizontalAlignment =
+                    if (horizontalAlignment == HORIZONTAL_ALIGN_CENTER) HORIZONTAL_ALIGN_START
+                    else horizontalAlignment,
+                style = style,
+                height = height
+            )
+        }
+    )
+
+/**
  * ProtoLayout Material3 clickable image button that doesn't offer additional slots, only image (for
  * example [backgroundImage] as a background.
  *
@@ -331,7 +460,11 @@
  *   parameter.
  * @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.
- * @param shape Defines the button's shape, in other words the corner radius for this button.
+ * @param shape Defines the button's shape, in other words the corner radius for this button. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param width The width of this button. It's highly recommended to set this to [expand] or
  *   [weight]
  * @param colors The colors used for this button. If not set, [ButtonDefaults.filledButtonColors]
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
index 491d263..dbb8d68 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
@@ -19,10 +19,14 @@
 import android.graphics.Color
 import androidx.annotation.Dimension
 import androidx.annotation.Dimension.Companion.DP
+import androidx.annotation.FloatRange
 import androidx.wear.protolayout.DimensionBuilders
+import androidx.wear.protolayout.DimensionBuilders.ContainerDimension
 import androidx.wear.protolayout.DimensionBuilders.expand
+import androidx.wear.protolayout.DimensionBuilders.weight
 import androidx.wear.protolayout.LayoutElementBuilders.Box
 import androidx.wear.protolayout.LayoutElementBuilders.Column
+import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_END
 import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_START
 import androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignment
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
@@ -81,6 +85,95 @@
     }
 
     /**
+     * Returns [LayoutElement] describing the inner content for the avatar shape button.
+     *
+     * This is a [Row] containing the following:
+     * * avatar
+     * * spacing if icon is present
+     * * labels that are in [Column]
+     *
+     * Additionally, horizontal padding and spacing for avatar and labels is weight based.
+     *
+     * [horizontalAlignment] defines side that avatar is.
+     */
+    internal fun buildContentForAvatarButton(
+        avatar: LayoutElement,
+        label: LayoutElement,
+        secondaryLabel: LayoutElement?,
+        @HorizontalAlignment horizontalAlignment: Int,
+        style: AvatarButtonStyle,
+        height: ContainerDimension,
+    ): LayoutElement {
+        val verticalElementBuilder: Column.Builder =
+            Column.Builder().setWidth(expand()).setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+        val horizontalElementBuilder: Row.Builder =
+            Row.Builder().setWidth(expand()).setHeight(height)
+
+        ContainerWithSpacersBuilder<LayoutElement>(
+                { it: LayoutElement? -> verticalElementBuilder.addContent(it!!) },
+                label
+            )
+            .addElement(secondaryLabel, horizontalSpacer(style.labelsSpaceDp))
+
+        // Side padding - start
+        horizontalElementBuilder.addContent(
+            verticalSpacer(
+                weight(
+                    if (horizontalAlignment == HORIZONTAL_ALIGN_START) style.avatarPaddingWeight
+                    else style.labelsPaddingWeight
+                )
+            )
+        )
+
+        // Wrap avatar in expandable box with weights
+        val wrapAvatar =
+            Box.Builder()
+                .setWidth(weight(style.avatarSizeWeight))
+                .setHeight(height)
+                .addContent(avatar)
+                .build()
+
+        if (horizontalAlignment == HORIZONTAL_ALIGN_START) {
+            horizontalElementBuilder.addContent(wrapAvatar)
+            horizontalElementBuilder.addContent(verticalSpacer(style.avatarToLabelsSpaceDp))
+        }
+
+        // Labels
+        horizontalElementBuilder.addContent(
+            Box.Builder()
+                .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                // Remaining % from 100% is for labels
+                .setWidth(
+                    weight(
+                        100 -
+                            style.avatarPaddingWeight -
+                            style.labelsPaddingWeight -
+                            style.avatarSizeWeight
+                    )
+                )
+                .addContent(verticalElementBuilder.build())
+                .build()
+        )
+
+        if (horizontalAlignment == HORIZONTAL_ALIGN_END) {
+            horizontalElementBuilder.addContent(verticalSpacer(style.avatarToLabelsSpaceDp))
+            horizontalElementBuilder.addContent(wrapAvatar)
+        }
+
+        // Side padding - end
+        horizontalElementBuilder.addContent(
+            verticalSpacer(
+                weight(
+                    if (horizontalAlignment == HORIZONTAL_ALIGN_START) style.labelsPaddingWeight
+                    else style.avatarPaddingWeight
+                )
+            )
+        )
+
+        return horizontalElementBuilder.build()
+    }
+
+    /**
      * Returns [LayoutElement] describing the inner content for the compact button.
      *
      * This is a [Row] wrapped inside of the Box for alignment, containing the following:
@@ -283,3 +376,50 @@
             )
     }
 }
+
+/** Provides style values for the avatar button component. */
+public class AvatarButtonStyle
+internal constructor(
+    @TypographyToken internal val labelTypography: Int,
+    @TypographyToken internal val secondaryLabelTypography: Int,
+    @FloatRange(from = 0.0, to = 100.0) internal val avatarSizeWeight: Float,
+    @FloatRange(from = 0.0, to = 100.0) internal val avatarPaddingWeight: Float,
+    @FloatRange(from = 0.0, to = 100.0) internal val labelsPaddingWeight: Float,
+    internal val innerVerticalPadding: Padding,
+    @Dimension(DP) internal val avatarToLabelsSpaceDp: Int,
+    @Dimension(DP) internal val labelsSpaceDp: Int,
+) {
+    public companion object {
+        /**
+         * Default style variation for the [avatarButton] where all opinionated inner content is
+         * displayed in a medium size.
+         */
+        public fun defaultAvatarButtonStyle(): AvatarButtonStyle =
+            AvatarButtonStyle(
+                labelTypography = Typography.LABEL_MEDIUM,
+                secondaryLabelTypography = Typography.BODY_SMALL,
+                avatarSizeWeight = 19.6f,
+                avatarPaddingWeight = 4.16f,
+                labelsPaddingWeight = 7.1f,
+                innerVerticalPadding = padding(vertical = 8f, horizontal = Float.NaN),
+                avatarToLabelsSpaceDp = 6,
+                labelsSpaceDp = 0
+            )
+
+        /**
+         * Default style variation for the [avatarButton] where all opinionated inner content is
+         * displayed in a large size.
+         */
+        public fun largeAvatarButtonStyle(): AvatarButtonStyle =
+            AvatarButtonStyle(
+                labelTypography = Typography.TITLE_MEDIUM,
+                secondaryLabelTypography = Typography.LABEL_SMALL,
+                avatarSizeWeight = 23.15f,
+                avatarPaddingWeight = 2.1f,
+                labelsPaddingWeight = 6f,
+                innerVerticalPadding = padding(vertical = 6f, horizontal = Float.NaN),
+                avatarToLabelsSpaceDp = 8,
+                labelsSpaceDp = 0
+            )
+    }
+}
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonGroup.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonGroup.kt
index eb1ec09..f38013d 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonGroup.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonGroup.kt
@@ -64,6 +64,8 @@
  * @param spacing The amount of spacing between buttons
  * @param content The content for each child. The UX guidance is to use no more than 3 elements
  *   within a this button group.
+ * @sample androidx.wear.protolayout.material3.samples.dataCardSample
+ * @sample androidx.wear.protolayout.material3.samples.oneSlotButtonsSample
  */
 // TODO: b/346958146 - Link visuals once they are available.
 public fun MaterialScope.buttonGroup(
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Card.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Card.kt
index 951a192..ef9b1cc 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Card.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Card.kt
@@ -38,6 +38,8 @@
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.defaultDataCardStyle
 import androidx.wear.protolayout.material3.GraphicDataCardDefaults.buildContentForGraphicDataCard
 import androidx.wear.protolayout.material3.GraphicDataCardStyle.Companion.defaultGraphicDataCardStyle
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.maxPrimaryLayoutMargins
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.minPrimaryLayoutMargins
 import androidx.wear.protolayout.material3.TitleCardDefaults.buildContentForTitleCard
 import androidx.wear.protolayout.material3.TitleCardStyle.Companion.defaultTitleCardStyle
 import androidx.wear.protolayout.modifiers.LayoutModifier
@@ -63,7 +65,11 @@
  *   expected to be a short piece of text. Uses [CardColors.timeColor] color by default.
  * @param height The height of this card. It's highly recommended to set this to [expand] or
  *   [weight].
- * @param shape Defines the card's shape, in other words the corner radius for this card.
+ * @param shape Defines the card's shape, in other words the corner radius for this card. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param colors The colors to be used for a background and inner content of this card. If the
  *   background image is also specified, the image will be laid out on top of the background color.
  *   In case of the fully opaque background image, then the background color will not be shown.
@@ -87,7 +93,6 @@
  * @sample androidx.wear.protolayout.material3.samples.titleCardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.titleCard(
     onClick: Clickable,
     title: (MaterialScope.() -> LayoutElement),
@@ -186,7 +191,11 @@
  * @param height The height of this card. It's highly recommended to leave this with default value
  *   as `wrap` if there's only 1 card on the screen. If there are two cards, it is highly
  *   recommended to set this to [expand] and use the smaller styles.
- * @param shape Defines the card's shape, in other words the corner radius for this card.
+ * @param shape Defines the card's shape, in other words the corner radius for this card. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param colors The colors to be used for a background and inner content of this card. If the
  *   background image is also specified, the image will be laid out on top of the background color.
  *   In case of the fully opaque background image, then the background color will not be shown.
@@ -207,7 +216,6 @@
  * @sample androidx.wear.protolayout.material3.samples.appCardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.appCard(
     onClick: Clickable,
     title: (MaterialScope.() -> LayoutElement),
@@ -313,7 +321,11 @@
  *   for the most optimal experience across different screen sizes.
  * @param height The height of this card. It's highly recommended to set this to [expand] for the
  *   most optimal experience across different screen sizes.
- * @param shape Defines the card's shape, in other words the corner radius for this card.
+ * @param shape Defines the card's shape, in other words the corner radius for this card. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param colors The colors to be used for a background and inner content of this card. If the
  *   background image is also specified, the image will be laid out on top of the background color.
  *   In case of the fully opaque background image, then the background color will not be shown.
@@ -339,7 +351,6 @@
  * @sample androidx.wear.protolayout.material3.samples.dataCardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.textDataCard(
     onClick: Clickable,
     title: (MaterialScope.() -> LayoutElement),
@@ -426,7 +437,11 @@
  *   for the most optimal experience across different screen sizes.
  * @param height The height of this card. It's highly recommended to set this to [expand] for the
  *   most optimal experience across different screen sizes.
- * @param shape Defines the card's shape, in other words the corner radius for this card.
+ * @param shape Defines the card's shape, in other words the corner radius for this card. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param colors The colors to be used for a background and inner content of this card. If the
  *   background image is also specified, the image will be laid out on top of the background color.
  *   In case of the fully opaque background image, then the background color will not be shown.
@@ -454,7 +469,6 @@
  * @sample androidx.wear.protolayout.material3.samples.dataCardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.iconDataCard(
     onClick: Clickable,
     title: (MaterialScope.() -> LayoutElement),
@@ -532,7 +546,11 @@
  * @param graphic A slot for displaying graphic data, such as progress indicator.
  * @param height The width of this card. It's highly recommended to set this to [expand] for the
  *   most optimal experience across different screen sizes.
- * @param shape Defines the card's shape, in other words the corner radius for this card.
+ * @param shape Defines the card's shape, in other words the corner radius for this card. If
+ *   changing these to radius smaller than [Shapes.medium], it is important to adjusts the margins
+ *   of [primaryLayout] used to accommodate for more space, for example by using
+ *   [maxPrimaryLayoutMargins]. Or, if the [shape] is set to [Shapes.full], using
+ *   [minPrimaryLayoutMargins] can be considered.
  * @param colors The colors to be used for a background and inner content of this card. Specified
  *   colors can be [CardDefaults.filledCardColors] for high emphasis card,
  *   [CardDefaults.filledVariantCardColors] for high/medium emphasis card,
@@ -552,7 +570,6 @@
  * @sample androidx.wear.protolayout.material3.samples.graphicDataCardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.graphicDataCard(
     onClick: Clickable,
     // TODO: b/368272767 - Potentially add helper for CPI and icon and link in KDocs.
@@ -627,7 +644,11 @@
  * @param modifier Modifiers to set to this element. It's highly recommended to set a content
  *   description using [contentDescription]. If [LayoutModifier.background] modifier is used and the
  *   the background image is also specified, the image will be laid out on top of this color. In
- *   case of the fully opaque background image, then the background color will not be shown.
+ *   case of the fully opaque background image, then the background color will not be shown. If
+ *   [LayoutModifier.clip] modifier is used to change the shape of the card to radius smaller than
+ *   [Shapes.medium], it is important to adjusts the margins of [primaryLayout] used to accommodate
+ *   for more space, for example by using [maxPrimaryLayoutMargins]. Or, if changing to
+ *   [Shapes.full], using [minPrimaryLayoutMargins] can be considered.
  * @param backgroundContent The background object to be used behind the content in the card. It is
  *   recommended to use the default styling that is automatically provided by only calling
  *   [backgroundImage] with the content. It can be combined with the specified
@@ -641,7 +662,6 @@
  * @sample androidx.wear.protolayout.material3.samples.cardSample
  */
 // TODO: b/346958146 - link Card visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
 public fun MaterialScope.card(
     onClick: Clickable,
     modifier: LayoutModifier = LayoutModifier,
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 8f080b0..f29af19 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
@@ -26,7 +26,6 @@
 import androidx.wear.protolayout.DimensionBuilders.ContainerDimension
 import androidx.wear.protolayout.DimensionBuilders.DpProp
 import androidx.wear.protolayout.DimensionBuilders.WrappedDimensionProp
-import androidx.wear.protolayout.DimensionBuilders.dp
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.DimensionBuilders.wrap
 import androidx.wear.protolayout.LayoutElementBuilders
@@ -44,6 +43,8 @@
 import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata
 import androidx.wear.protolayout.ModifiersBuilders.Padding
 import androidx.wear.protolayout.ModifiersBuilders.SEMANTICS_ROLE_BUTTON
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.percentageHeightToDp
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.percentageWidthToDp
 import androidx.wear.protolayout.materialcore.fontscaling.FontScaleConverterFactory
 import androidx.wear.protolayout.modifiers.LayoutModifier
 import androidx.wear.protolayout.modifiers.clickable
@@ -53,6 +54,7 @@
 import androidx.wear.protolayout.modifiers.toProtoLayoutModifiers
 import androidx.wear.protolayout.types.LayoutColor
 import androidx.wear.protolayout.types.argb
+import androidx.wear.protolayout.types.dp
 import java.nio.charset.StandardCharsets
 
 /**
@@ -62,7 +64,7 @@
 internal const val SCREEN_SIZE_BREAKPOINT_DP = 225
 
 /** Minimum tap target for any clickable element. */
-internal val MINIMUM_TAP_TARGET_SIZE: DpProp = dp(48f)
+internal val MINIMUM_TAP_TARGET_SIZE: DpProp = 48f.dp
 
 /** Returns byte array representation of tag from String. */
 internal fun String.toTagBytes(): ByteArray = toByteArray(StandardCharsets.UTF_8)
@@ -89,7 +91,7 @@
 
 @Dimension(unit = SP) private fun Float.dpToSpLinear(fontScale: Float): Float = this / fontScale
 
-internal fun Int.toDp() = dp(this.toFloat())
+internal fun Int.toDp() = this.toFloat().dp
 
 /** Builds a horizontal Spacer, with width set to expand and height set to the given value. */
 internal fun horizontalSpacer(@Dimension(unit = DP) heightDp: Int): Spacer =
@@ -206,3 +208,33 @@
         )
         .build()
 }
+
+/**
+ * Returns [Padding] objects with values represented as percentages from the screen size.
+ *
+ * @param start The ratio percentage of the screen width that should be use as start padding
+ * @param end The ratio percentage of the screen width that should be use as end padding
+ * @param bottom The ratio percentage of the screen width that should be use as bottom padding
+ */
+internal fun MaterialScope.percentagePadding(
+    @FloatRange(from = 0.0, to = 1.0) start: Float,
+    @FloatRange(from = 0.0, to = 1.0) end: Float,
+    @FloatRange(from = 0.0, to = 1.0) bottom: Float
+): Padding =
+    padding(
+        start = percentageWidthToDp(start),
+        end = percentageWidthToDp(end),
+        bottom = percentageHeightToDp(bottom)
+    )
+
+/**
+ * Returns [Padding] objects with values represented as percentages from the screen size, using only
+ * horizontal padding.
+ *
+ * @param start The ratio percentage of the screen width that should be use as start padding
+ * @param end The ratio percentage of the screen width that should be use as end padding
+ */
+internal fun MaterialScope.percentagePadding(
+    @FloatRange(from = 0.0, to = 1.0) start: Float,
+    @FloatRange(from = 0.0, to = 1.0) end: Float
+): Padding = padding(start = percentageWidthToDp(start), end = percentageWidthToDp(end))
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 6b9a14b..d547b3f 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
@@ -73,6 +73,7 @@
     internal val defaultIconStyle: IconStyle,
     internal val defaultBackgroundImageStyle: BackgroundImageStyle,
     internal val defaultAvatarImageStyle: AvatarImageStyle,
+    internal val layoutSlotsPresence: LayoutSlotsPresence
 ) {
     /** Color Scheme used within this scope and its components. */
     public val colorScheme: ColorScheme = theme.colorScheme
@@ -84,7 +85,8 @@
         defaultTextElementStyle: TextElementStyle = this.defaultTextElementStyle,
         defaultIconStyle: IconStyle = this.defaultIconStyle,
         defaultBackgroundImageStyle: BackgroundImageStyle = this.defaultBackgroundImageStyle,
-        defaultAvatarImageStyle: AvatarImageStyle = this.defaultAvatarImageStyle
+        defaultAvatarImageStyle: AvatarImageStyle = this.defaultAvatarImageStyle,
+        layoutSlotsPresence: LayoutSlotsPresence = this.layoutSlotsPresence
     ): MaterialScope =
         MaterialScope(
             context = context,
@@ -94,7 +96,8 @@
             defaultTextElementStyle = defaultTextElementStyle,
             defaultIconStyle = defaultIconStyle,
             defaultBackgroundImageStyle = defaultBackgroundImageStyle,
-            defaultAvatarImageStyle = defaultAvatarImageStyle
+            defaultAvatarImageStyle = defaultAvatarImageStyle,
+            layoutSlotsPresence = layoutSlotsPresence
         )
 }
 
@@ -140,7 +143,8 @@
             defaultTextElementStyle = TextElementStyle(),
             defaultIconStyle = IconStyle(),
             defaultBackgroundImageStyle = BackgroundImageStyle(),
-            defaultAvatarImageStyle = AvatarImageStyle()
+            defaultAvatarImageStyle = AvatarImageStyle(),
+            layoutSlotsPresence = LayoutSlotsPresence()
         )
         .layout()
 
@@ -180,3 +184,9 @@
     @ContentScaleMode
     val contentScaleMode: Int = LayoutElementBuilders.CONTENT_SCALE_MODE_FILL_BOUNDS
 )
+
+internal class LayoutSlotsPresence(
+    val isTitleSlotPresent: Boolean = false,
+    val isBottomSlotEdgeButton: Boolean = false,
+    val isBottomSlotPresent: Boolean = isBottomSlotEdgeButton
+)
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayout.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayout.kt
index 0bd6491..39019fa 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayout.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayout.kt
@@ -18,11 +18,11 @@
 
 import androidx.annotation.Dimension
 import androidx.annotation.Dimension.Companion.DP
+import androidx.annotation.FloatRange
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
 import androidx.wear.protolayout.DimensionBuilders
 import androidx.wear.protolayout.DimensionBuilders.DpProp
-import androidx.wear.protolayout.DimensionBuilders.dp
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.DimensionBuilders.wrap
 import androidx.wear.protolayout.LayoutElementBuilders.Box
@@ -33,25 +33,39 @@
 import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers
 import androidx.wear.protolayout.ModifiersBuilders.Padding
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.defaultPrimaryLayoutMargins
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.maxBottomMargin
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.maxPrimaryLayoutMargins
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.maxSideMargin
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.midPrimaryLayoutMargins
+import androidx.wear.protolayout.material3.PredefinedPrimaryLayoutMargins.minPrimaryLayoutMargins
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_EDGE_BUTTON_TOP_MARGIN_DP
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_EMPTY_MARGIN_BOTTOM_PERCENTAGE
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_MARGIN_BOTTOM_PERCENTAGE
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_MARGIN_SIDE_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_BOTTOM_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_TOP_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_BOTTOM_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_TOP_PERCENTAGE
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.BOTTOM_SLOT_OTHER_MARGIN_TOP_DP
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.FOOTER_LABEL_SLOT_MARGIN_SIDE_PERCENTAGE
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.FOOTER_LABEL_TO_BOTTOM_SLOT_SPACER_HEIGHT_DP
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_ICON_SIZE_DP
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_ICON_TITLE_SPACER_HEIGHT_DP
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_ICON_TITLE_SPACER_HEIGHT_LARGE_DP
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_ICON_TITLE_SPACER_HEIGHT_SMALL_DP
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_MARGIN_BOTTOM_DP
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_MARGIN_SIDE_PERCENTAGE
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.HEADER_MARGIN_TOP_DP
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.MAIN_SLOT_WITH_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE
-import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.MAIN_SLOT_WITH_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE
 import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.METADATA_TAG
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.percentageHeightToDp
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.DEFAULT_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MID_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MIN_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.customizedPrimaryLayoutMargin
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.DEFAULT
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MAX
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MID
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MIN
+import androidx.wear.protolayout.modifiers.LayoutModifier
+import androidx.wear.protolayout.modifiers.padding
+import androidx.wear.protolayout.modifiers.toProtoLayoutModifiers
+import androidx.wear.protolayout.types.dp
 
 /**
  * ProtoLayout Material3 full screen layout that represents a suggested Material3 layout style that
@@ -99,19 +113,31 @@
  *   it an edge button, the given label will be ignored.
  * @param onClick The clickable action for whole layout. If any area (outside of other added
  *   tappable components) is clicked, it will fire the associated action.
+ * @param margins The customized outer margin that will be applied as following:
+ *     * `start` and `end` would be applied as a side margins on [mainSlot]
+ *     * `bottom` would be applied as a bottom margin when [bottomSlot] is not present.
+ *
+ *   It is highly recommended to use provided constants for these
+ *   margins - [DEFAULT_PRIMARY_LAYOUT_MARGIN], [MIN_PRIMARY_LAYOUT_MARGIN],
+ *   [MID_PRIMARY_LAYOUT_MARGIN] or [MAX_PRIMARY_LAYOUT_MARGIN], depending on inner content and its
+ *   corners shape. If providing custom numbers by [customizedPrimaryLayoutMargin], it is a
+ *   requirement for those to be percentages of the screen width and height.
+ *
  * @sample androidx.wear.protolayout.material3.samples.topLevelLayout
+ * @sample androidx.wear.protolayout.material3.samples.cardSample
+ * @sample androidx.wear.protolayout.material3.samples.oneSlotButtonsSample
+ * @sample androidx.wear.protolayout.material3.samples.graphicDataCardSample
  */
-// TODO: b/356568440 - Add sample above and put it in a proper samples file and link with @sample
 // TODO: b/346958146 - Link visuals once they are available.
 // TODO: b/353247528 - Handle the icon.
-// TODO: b/369162409 -Allow side and bottom margins in PrimaryLayout to be customizable.
 // TODO: b/370976767 - Specify that this should be used with MaterialTileService.
 public fun MaterialScope.primaryLayout(
     mainSlot: (MaterialScope.() -> LayoutElement),
     titleSlot: (MaterialScope.() -> LayoutElement)? = null,
     bottomSlot: (MaterialScope.() -> LayoutElement)? = null,
     labelForBottomSlot: (MaterialScope.() -> LayoutElement)? = null,
-    onClick: Clickable? = null
+    onClick: Clickable? = null,
+    margins: PrimaryLayoutMargins = DEFAULT_PRIMARY_LAYOUT_MARGIN
 ): LayoutElement =
     primaryLayoutWithOverrideIcon(
         overrideIcon = false,
@@ -119,7 +145,8 @@
         mainSlot = mainSlot,
         bottomSlot = bottomSlot,
         labelForBottomSlot = labelForBottomSlot,
-        onClick = onClick
+        onClick = onClick,
+        margins = margins
     )
 
 /**
@@ -135,6 +162,7 @@
     bottomSlot: (MaterialScope.() -> LayoutElement)? = null,
     labelForBottomSlot: (MaterialScope.() -> LayoutElement)? = null,
     onClick: Clickable? = null,
+    margins: PrimaryLayoutMargins = DEFAULT_PRIMARY_LAYOUT_MARGIN
 ): LayoutElement {
     val screenWidth = deviceConfiguration.screenWidthDp
     val screenHeight = deviceConfiguration.screenHeightDp
@@ -156,19 +184,6 @@
 
     onClick?.apply { modifiers.setClickable(this) }
 
-    val mainSlotSideMargin: DpProp =
-        dp(
-            screenWidth *
-                if (bottomSlot != null)
-                    (if (titleSlot != null)
-                        MAIN_SLOT_WITH_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE
-                    else MAIN_SLOT_WITH_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE)
-                else
-                    (if (titleSlot != null)
-                        MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE
-                    else MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE)
-        )
-
     val mainLayout =
         Column.Builder()
             .setModifiers(modifiers.build())
@@ -191,19 +206,60 @@
                 )
             )
 
+    val bottomSlotValue = bottomSlot?.let { bottomSlot() }
+
+    val marginsValues: Padding =
+        withStyle(
+                layoutSlotsPresence =
+                    LayoutSlotsPresence(
+                        isTitleSlotPresent = titleSlot != null,
+                        isBottomSlotPresent = bottomSlot != null,
+                        isBottomSlotEdgeButton = bottomSlotValue?.isSlotEdgeButton() == true
+                    )
+            )
+            .let { scope ->
+                if (margins is PrimaryLayoutMarginsImpl) {
+                    when (margins.size) {
+                        MIN -> scope.minPrimaryLayoutMargins()
+                        MID -> scope.midPrimaryLayoutMargins()
+                        MAX -> scope.maxPrimaryLayoutMargins()
+                        DEFAULT -> scope.defaultPrimaryLayoutMargins()
+                        else -> scope.defaultPrimaryLayoutMargins()
+                    }
+                } else if (margins is CustomPrimaryLayoutMargins) {
+                    margins.toPadding(scope)
+                } else {
+                    // Fallback to default
+                    scope.defaultPrimaryLayoutMargins()
+                }
+            }
+
     // Contains main content. This Box is needed to set to expand, even if empty so it
     // fills the empty space until bottom content.
-    mainSlot?.let { mainLayout.addContent(mainSlot().getMainContentBox(mainSlotSideMargin)) }
+    mainSlot?.let {
+        mainLayout.addContent(
+            mainSlot()
+                .getMainContentBox(
+                    sideMargins = marginsValues,
+                    maxSideMarginFallbackDp = maxSideMargin()
+                )
+        )
+    }
 
     // Contains bottom slot, optional label or needed padding if empty.
-    mainLayout.addContent(getFooterContent(bottomSlot?.let { bottomSlot() }, labelSlot))
+    mainLayout.addContent(
+        getFooterContent(
+            bottomSlot = bottomSlotValue,
+            labelSlot = labelSlot,
+            bottomMarginForNoContentDp = marginsValues.bottom?.value ?: maxBottomMargin()
+        )
+    )
 
     return mainLayout.build()
 }
 
 private fun MaterialScope.getIconPlaceholder(overrideIcon: Boolean): LayoutElement {
-    val iconSlot =
-        Box.Builder().setWidth(HEADER_ICON_SIZE_DP.toDp()).setHeight(HEADER_ICON_SIZE_DP.toDp())
+    val iconSlot = Box.Builder().setWidth(HEADER_ICON_SIZE_DP.dp).setHeight(HEADER_ICON_SIZE_DP.dp)
     if (overrideIcon) {
         iconSlot.setModifiers(
             Modifiers.Builder()
@@ -233,7 +289,13 @@
 
     titleSlot?.apply {
         headerBuilder
-            .addContent(horizontalSpacer(HEADER_ICON_TITLE_SPACER_HEIGHT_DP))
+            .addContent(
+                horizontalSpacer(
+                    if (deviceConfiguration.screenHeightDp.isBreakpoint())
+                        HEADER_ICON_TITLE_SPACER_HEIGHT_LARGE_DP
+                    else HEADER_ICON_TITLE_SPACER_HEIGHT_SMALL_DP
+                )
+            )
             .addContent(titleSlot)
     }
 
@@ -241,22 +303,25 @@
 }
 
 /** Returns central slot with the optional main content. It expands to fill the available space. */
-private fun LayoutElement.getMainContentBox(sideMargin: DpProp): Box =
-    Box.Builder()
+private fun LayoutElement.getMainContentBox(
+    sideMargins: Padding,
+    maxSideMarginFallbackDp: Float,
+): Box {
+    // Start and end Padding shouldn't be null if these are predefined margins, but if developers
+    // sets some other object, we will fallback to the max margin.
+    val sideMarginStart = sideMargins.start?.value ?: maxSideMarginFallbackDp
+    val sideMarginEnd = sideMargins.end?.value ?: maxSideMarginFallbackDp
+    return Box.Builder()
         .setWidth(expand())
         .setHeight(expand())
         .setModifiers(
-            Modifiers.Builder()
-                .setPadding(
-                    Padding.Builder() // Top and bottom space has been added to other elements.
-                        .setStart(sideMargin)
-                        .setEnd(sideMargin)
-                        .build()
-                )
-                .build()
+            // Top and bottom space has been added to other elements.
+            LayoutModifier.padding(start = sideMarginStart, end = sideMarginEnd)
+                .toProtoLayoutModifiers()
         )
         .addContent(this)
         .build()
+}
 
 /**
  * Returns the footer content, containing bottom slot and optional label with the corresponding
@@ -265,22 +330,19 @@
  */
 private fun MaterialScope.getFooterContent(
     bottomSlot: LayoutElement?,
-    labelSlot: LayoutElement?
+    labelSlot: LayoutElement?,
+    bottomMarginForNoContentDp: Float
 ): LayoutElement {
     val footer = Box.Builder().setWidth(wrap()).setHeight(wrap())
 
     if (bottomSlot == null) {
         footer.setWidth(expand())
-        footer.setHeight(
-            dp(BOTTOM_SLOT_EMPTY_MARGIN_BOTTOM_PERCENTAGE * deviceConfiguration.screenHeightDp)
-        )
+        footer.setHeight(bottomMarginForNoContentDp.dp)
     } else if (bottomSlot.isSlotEdgeButton()) {
         // Label shouldn't be used with EdgeButton.
         footer.setModifiers(
             Modifiers.Builder()
-                .setPadding(
-                    Padding.Builder().setTop(BOTTOM_EDGE_BUTTON_TOP_MARGIN_DP.toDp()).build()
-                )
+                .setPadding(Padding.Builder().setTop(BOTTOM_EDGE_BUTTON_TOP_MARGIN_DP.dp).build())
                 .build()
         )
 
@@ -292,21 +354,10 @@
             Modifiers.Builder()
                 .setPadding(
                     Padding.Builder()
-                        .setTop(
-                            dp(
-                                (if (labelSlot == null)
-                                    BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_TOP_PERCENTAGE
-                                else BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_TOP_PERCENTAGE) *
-                                    deviceConfiguration.screenHeightDp
-                            )
-                        )
+                        .setTop(BOTTOM_SLOT_OTHER_MARGIN_TOP_DP.dp)
                         .setBottom(
-                            dp(
-                                (if (labelSlot == null)
-                                    BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_BOTTOM_PERCENTAGE
-                                else BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_BOTTOM_PERCENTAGE) *
-                                    deviceConfiguration.screenHeightDp
-                            )
+                            percentageHeightToDp(BOTTOM_SLOT_OTHER_MARGIN_BOTTOM_PERCENTAGE / 100)
+                                .dp
                         )
                         .build()
                 )
@@ -317,10 +368,9 @@
             otherBottomSlot
                 .addContent(
                     generateLabelContent(
-                        dp(
-                            FOOTER_LABEL_SLOT_MARGIN_SIDE_PERCENTAGE *
-                                deviceConfiguration.screenWidthDp
-                        )
+                        (FOOTER_LABEL_SLOT_MARGIN_SIDE_PERCENTAGE *
+                                deviceConfiguration.screenWidthDp)
+                            .dp
                     )
                 )
                 .addContent(horizontalSpacer(FOOTER_LABEL_TO_BOTTOM_SLOT_SPACER_HEIGHT_DP))
@@ -330,10 +380,9 @@
             otherBottomSlot
                 .addContent(
                     bottomSlot.generateBottomSlotContent(
-                        dp(
-                            BOTTOM_SLOT_OTHER_MARGIN_SIDE_PERCENTAGE *
-                                deviceConfiguration.screenWidthDp
-                        )
+                        (BOTTOM_SLOT_OTHER_MARGIN_SIDE_PERCENTAGE *
+                                deviceConfiguration.screenWidthDp)
+                            .dp
                     )
                 )
                 .build()
@@ -363,47 +412,47 @@
         .addContent(this)
         .build()
 
-private fun MaterialScope.getMarginForHeader(): Padding {
-    return Padding.Builder()
-        .setTop(HEADER_MARGIN_TOP_DP.toDp())
-        .setBottom(HEADER_MARGIN_BOTTOM_DP.toDp())
-        .setStart(dp(HEADER_MARGIN_SIDE_PERCENTAGE * deviceConfiguration.screenWidthDp))
-        .setEnd(dp(HEADER_MARGIN_SIDE_PERCENTAGE * deviceConfiguration.screenWidthDp))
-        .build()
-}
+private fun MaterialScope.getMarginForHeader() =
+    padding(
+        top = HEADER_MARGIN_TOP_DP,
+        bottom = HEADER_MARGIN_BOTTOM_DP,
+        start = HEADER_MARGIN_SIDE_PERCENTAGE * deviceConfiguration.screenWidthDp,
+        end = HEADER_MARGIN_SIDE_PERCENTAGE * deviceConfiguration.screenWidthDp
+    )
 
 /** Contains the default values used by Material layout. */
 internal object PrimaryLayoutDefaults {
+    internal fun MaterialScope.percentageWidthToDp(
+        @FloatRange(from = 0.0, to = 1.0) percentage: Float
+    ): Float = percentage * deviceConfiguration.screenWidthDp
+
+    internal fun MaterialScope.percentageHeightToDp(
+        @FloatRange(from = 0.0, to = 1.0) percentage: Float
+    ): Float = percentage * deviceConfiguration.screenHeightDp
+
     /** Tool tag for Metadata in Modifiers, so we know that Row is actually a PrimaryLayout. */
-    @VisibleForTesting const val METADATA_TAG: String = "M3_PL"
+    @VisibleForTesting internal const val METADATA_TAG: String = "M3_PL"
 
-    @Dimension(unit = DP) const val HEADER_MARGIN_TOP_DP: Int = 3
+    @Dimension(DP) internal const val HEADER_MARGIN_TOP_DP = 3f
 
-    @Dimension(unit = DP) const val HEADER_MARGIN_BOTTOM_DP: Int = 6
+    @Dimension(DP) internal const val HEADER_MARGIN_BOTTOM_DP = 6f
 
-    const val HEADER_MARGIN_SIDE_PERCENTAGE: Float = 14.5f / 100
+    internal const val HEADER_MARGIN_SIDE_PERCENTAGE = 14.5f / 100
 
-    @Dimension(unit = DP) const val HEADER_ICON_SIZE_DP: Int = 24
+    @Dimension(DP) internal const val HEADER_ICON_SIZE_DP = 24f
 
-    @Dimension(unit = DP) const val HEADER_ICON_TITLE_SPACER_HEIGHT_DP: Int = 2
+    @Dimension(DP) internal const val HEADER_ICON_TITLE_SPACER_HEIGHT_SMALL_DP = 2
+    @Dimension(DP) internal const val HEADER_ICON_TITLE_SPACER_HEIGHT_LARGE_DP = 4
 
     // The remaining margins around EdgeButton are within the component itself.
-    @Dimension(unit = DP) const val BOTTOM_EDGE_BUTTON_TOP_MARGIN_DP: Int = 4
+    @Dimension(DP) internal const val BOTTOM_EDGE_BUTTON_TOP_MARGIN_DP = 4f
 
-    const val BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_TOP_PERCENTAGE: Float = 4f / 100
-    const val BOTTOM_SLOT_OTHER_NO_LABEL_MARGIN_BOTTOM_PERCENTAGE: Float = 8.3f / 100
+    @Dimension(DP) internal const val BOTTOM_SLOT_OTHER_MARGIN_TOP_DP = 6f
+    internal const val BOTTOM_SLOT_OTHER_MARGIN_BOTTOM_PERCENTAGE = 5.2f
 
-    const val BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_TOP_PERCENTAGE: Float = 3f / 100
-    const val BOTTOM_SLOT_OTHER_WITH_LABEL_MARGIN_BOTTOM_PERCENTAGE: Float = 5f / 100
-    const val BOTTOM_SLOT_OTHER_MARGIN_SIDE_PERCENTAGE: Float = 26f / 100
+    internal const val BOTTOM_SLOT_OTHER_MARGIN_SIDE_PERCENTAGE = 26f / 100
 
-    @Dimension(unit = DP) const val FOOTER_LABEL_TO_BOTTOM_SLOT_SPACER_HEIGHT_DP: Int = 2
+    @Dimension(DP) internal const val FOOTER_LABEL_TO_BOTTOM_SLOT_SPACER_HEIGHT_DP = 2
 
-    const val FOOTER_LABEL_SLOT_MARGIN_SIDE_PERCENTAGE: Float = 16.64f / 100
-
-    const val BOTTOM_SLOT_EMPTY_MARGIN_BOTTOM_PERCENTAGE: Float = 14f / 100
-    const val MAIN_SLOT_WITH_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE: Float = 3f / 100
-    const val MAIN_SLOT_WITH_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE: Float = 6f / 100
-    const val MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITH_TITLE_MARGIN_SIDE_PERCENTAGE: Float = 7.3f / 100
-    const val MAIN_SLOT_WITHOUT_BOTTOM_SLOT_WITHOUT_TITLE_MARGIN_SIDE_PERCENTAGE: Float = 8.3f / 100
+    internal const val FOOTER_LABEL_SLOT_MARGIN_SIDE_PERCENTAGE = 16.64f / 100
 }
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayoutMargins.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayoutMargins.kt
new file mode 100644
index 0000000..d38e0c5
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/PrimaryLayoutMargins.kt
@@ -0,0 +1,505 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.annotation.FloatRange
+import androidx.annotation.IntDef
+import androidx.annotation.RestrictTo
+import androidx.wear.protolayout.ModifiersBuilders.Padding
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.percentageHeightToDp
+import androidx.wear.protolayout.material3.PrimaryLayoutDefaults.percentageWidthToDp
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.DEFAULT_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MID_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MIN_PRIMARY_LAYOUT_MARGIN
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.DEFAULT
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MAX
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MID
+import androidx.wear.protolayout.material3.PrimaryLayoutMarginsImpl.Companion.MIN
+import kotlin.Float.Companion.NaN
+
+/**
+ * The set of margins for the [primaryLayout]'s customization.
+ *
+ * It is highly recommended to use these predefined values that are optimized for different screen
+ * sizes, content's corners and slots presences. Those are:
+ * * [MIN_PRIMARY_LAYOUT_MARGIN]
+ * * [MID_PRIMARY_LAYOUT_MARGIN]
+ * * [DEFAULT_PRIMARY_LAYOUT_MARGIN]
+ * * [MAX_PRIMARY_LAYOUT_MARGIN].
+ */
+public abstract class PrimaryLayoutMargins internal constructor() {
+    public companion object {
+        /**
+         * Default side margins for the main slot of [primaryLayout] that works for the majority of
+         * [Shapes] inside the main content components, usually across round toward medium round
+         * corners.
+         *
+         * The actual returned values depend on presence of slots in [primaryLayout] which will be
+         * applied automatically.
+         */
+        @JvmField
+        public val DEFAULT_PRIMARY_LAYOUT_MARGIN: PrimaryLayoutMargins =
+            PrimaryLayoutMarginsImpl(DEFAULT)
+
+        /**
+         * Min side margins for the main slot of [primaryLayout] that should be used only when the
+         * main slot contains content components with fully rounded corners, such as [Shapes.full]
+         * to avoid clipping.
+         *
+         * The actual returned values depend on presence of slots in [primaryLayout] which will be
+         * applied automatically.
+         */
+        @JvmField
+        public val MIN_PRIMARY_LAYOUT_MARGIN: PrimaryLayoutMargins = PrimaryLayoutMarginsImpl(MIN)
+
+        /**
+         * Mid side margins for the main slot of [primaryLayout] that should be used when the main
+         * slot contains content components with fully rounded to medium round corners, for example,
+         * larger than [Shapes.medium] to avoid clipping.
+         *
+         * The actual returned values depend on presence of slots in [primaryLayout] which will be
+         * applied automatically.
+         */
+        @JvmField
+        public val MID_PRIMARY_LAYOUT_MARGIN: PrimaryLayoutMargins = PrimaryLayoutMarginsImpl(MID)
+
+        /**
+         * Max side margins for the main slot of [primaryLayout] that should be used when the main
+         * slot contains content components with square corners, for example, smaller than
+         * [Shapes.medium] to avoid clipping.
+         *
+         * The actual returned values depend on presence of slots in [primaryLayout] which will be
+         * applied automatically.
+         */
+        @JvmField
+        public val MAX_PRIMARY_LAYOUT_MARGIN: PrimaryLayoutMargins = PrimaryLayoutMarginsImpl(MAX)
+
+        /**
+         * Creates new set of margins to be used for [primaryLayout] customization. The passed in
+         * values represent percentages based on the screen width.
+         *
+         * It is highly recommended to use predefined values instead of creating this custom one,
+         * because they are optimized for different screen sizes, content's corners and slots
+         * presences. Those predefined ones are:
+         * * [MIN_PRIMARY_LAYOUT_MARGIN]
+         * * [MID_PRIMARY_LAYOUT_MARGIN]
+         * * [DEFAULT_PRIMARY_LAYOUT_MARGIN]
+         * * [MAX_PRIMARY_LAYOUT_MARGIN].
+         *
+         * @param start Percentage of the screen width that should be applied as margin on the start
+         *   side
+         * @param end Percentage of the screen width that should be applied as margin on the end
+         *   side
+         */
+        public fun customizedPrimaryLayoutMargin(
+            @FloatRange(from = 0.0, to = 1.0) start: Float,
+            @FloatRange(from = 0.0, to = 1.0) end: Float
+        ): PrimaryLayoutMargins = CustomPrimaryLayoutMargins(start = start, end = end)
+
+        /**
+         * Creates new set of margins to be used for [primaryLayout] customization. The passed in
+         * values represent percentages based on the screen width and screen height.
+         *
+         * It is highly recommended to use predefined values instead of creating this custom one,
+         * because they are optimized for different screen sizes, content's corners and slots
+         * presences. Those predefined ones are:
+         * * [MIN_PRIMARY_LAYOUT_MARGIN]
+         * * [MID_PRIMARY_LAYOUT_MARGIN]
+         * * [DEFAULT_PRIMARY_LAYOUT_MARGIN]
+         * * [MAX_PRIMARY_LAYOUT_MARGIN].
+         *
+         * @param start Percentage of the screen width that should be applied as margin on the start
+         *   side
+         * @param end Percentage of the screen width that should be applied as margin on the end
+         *   side
+         * @param bottom Percentage of the screen height that should be applied as margin on the
+         *   bottom
+         */
+        public fun customizedPrimaryLayoutMargin(
+            @FloatRange(from = 0.0, to = 1.0) start: Float,
+            @FloatRange(from = 0.0, to = 1.0) end: Float,
+            @FloatRange(from = 0.0, to = 1.0) bottom: Float
+        ): PrimaryLayoutMargins =
+            CustomPrimaryLayoutMargins(start = start, end = end, bottom = bottom)
+    }
+}
+
+/**
+ * The predefined set of margin style sizes to be used by [primaryLayout] tod define default values.
+ */
+internal class PrimaryLayoutMarginsImpl internal constructor(internal val size: Int) :
+    PrimaryLayoutMargins() {
+    companion object {
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        @Retention(AnnotationRetention.SOURCE)
+        @IntDef(DEFAULT, MIN, MID, MAX)
+        annotation class PrimaryLayoutStyleSizes
+
+        internal const val DEFAULT = 0
+        internal const val MIN = 1
+        internal const val MID = 2
+        internal const val MAX = 3
+    }
+}
+
+/**
+ * The custom set of margins for the [primaryLayout]'s customization.
+ *
+ * It is highly recommended to use predefined values instead of creating this custom once, because
+ * they are optimized for different screen sizes, content's corners and slots presences. Those
+ * predefined once are:
+ * * [MIN_PRIMARY_LAYOUT_MARGIN]
+ * * [MID_PRIMARY_LAYOUT_MARGIN]
+ * * [DEFAULT_PRIMARY_LAYOUT_MARGIN]
+ * * [MAX_PRIMARY_LAYOUT_MARGIN].
+ */
+internal class CustomPrimaryLayoutMargins
+/**
+ * Creates new set of margins to be used for [primaryLayout] customization. The passed in values
+ * represent percentages based on the screen width.
+ *
+ * @param start Percentage of the screen width that should be applied as margin on the start side
+ * @param end Percentage of the screen width that should be applied as margin on the end side
+ */
+(
+    @FloatRange(from = 0.0, to = 1.0) internal val start: Float,
+    @FloatRange(from = 0.0, to = 1.0) internal val end: Float
+) : PrimaryLayoutMargins() {
+    internal var bottom: Float = NaN
+
+    /**
+     * Creates new set of margins to be used for [primaryLayout] customization. The passed in values
+     * represent percentages based on the screen width and screen height.
+     *
+     * @param start Percentage of the screen width that should be applied as margin on the start
+     *   side
+     * @param end Percentage of the screen width that should be applied as margin on the end side
+     * @param bottom Percentage of the screen height that should be applied as margin on the bottom
+     */
+    constructor(
+        @FloatRange(from = 0.0, to = 1.0) start: Float,
+        @FloatRange(from = 0.0, to = 1.0) end: Float,
+        @FloatRange(from = 0.0, to = 1.0) bottom: Float
+    ) : this(start = start, end = end) {
+        this.bottom = bottom
+    }
+
+    /** Returns the given margins as [Padding] object. */
+    internal fun toPadding(scope: MaterialScope): Padding =
+        if (bottom.isNaN()) {
+            scope.percentagePadding(start = start, end = end)
+        } else {
+            scope.percentagePadding(start = start, end = end, bottom = bottom)
+        }
+}
+
+/**
+ * Default values for margins used in [primaryLayout] based on slots presence from [materialScope].
+ */
+internal object PredefinedPrimaryLayoutMargins {
+    /**
+     * Default side margins for the main slot of [primaryLayout] that works for the majority of
+     * [Shapes] inside the main content components, usually across round toward medium round
+     * corners.
+     *
+     * The actual returned values depend on presence of slots in [primaryLayout] which will be
+     * applied automatically.
+     */
+    fun MaterialScope.defaultPrimaryLayoutMargins(): Padding =
+        if (layoutSlotsPresence.isTitleSlotPresent) {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    defaultPrimaryLayoutMarginsWithTitleWithEdgeButton()
+                else defaultPrimaryLayoutMarginsWithBottomSlotAsOther()
+            } else {
+                defaultPrimaryLayoutMarginsWithTitleWithoutBottomSlot()
+            }
+        } else {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    defaultPrimaryLayoutMarginsWithoutTitleWithEdgeButton()
+                else defaultPrimaryLayoutMarginsWithBottomSlotAsOther()
+            } else {
+                defaultPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot()
+            }
+        }
+
+    /**
+     * Min side margins for the main slot of [primaryLayout] that should be used only when the main
+     * slot contains content components with fully rounded corners, such as [Shapes.full] to avoid
+     * clipping.
+     *
+     * The actual returned values depend on presence of slots in [primaryLayout] which will be
+     * applied automatically.
+     */
+    internal fun MaterialScope.minPrimaryLayoutMargins(): Padding =
+        // Values are the same regardless of title slot presence.
+        if (layoutSlotsPresence.isBottomSlotPresent) {
+            if (layoutSlotsPresence.isBottomSlotEdgeButton) minPrimaryLayoutMarginsWithEdgeButton()
+            else minPrimaryLayoutMarginsWithBottomSlotAsOther()
+        } else {
+            minPrimaryLayoutMarginsWithoutBottomSlot()
+        }
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains content components with fully rounded to medium round corners, for example, larger
+     * than [Shapes.medium] to avoid clipping.
+     *
+     * The actual returned values depend on presence of slots in [primaryLayout] which will be
+     * applied automatically.
+     */
+    internal fun MaterialScope.midPrimaryLayoutMargins(): Padding =
+        if (layoutSlotsPresence.isTitleSlotPresent) {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    midPrimaryLayoutMarginsWithTitleWithEdgeButton()
+                else midPrimaryLayoutMarginsWithTitleWithBottomSlotAsOther()
+            } else {
+                midPrimaryLayoutMarginsWithTitleWithoutBottomSlot()
+            }
+        } else {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    midPrimaryLayoutMarginsWithoutTitleWithEdgeButton()
+                else midPrimaryLayoutMarginsWithoutTitleWithBottomSlotAsOther()
+            } else {
+                midPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot()
+            }
+        }
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains content components with square corners, for example, smaller than [Shapes.medium] to
+     * avoid clipping.
+     *
+     * The actual returned values depend on presence of slots in [primaryLayout] which will be
+     * applied automatically.
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMargins(): Padding =
+        if (layoutSlotsPresence.isTitleSlotPresent) {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    maxPrimaryLayoutMarginsWithTitleWithEdgeButton()
+                else maxPrimaryLayoutMarginsWithTitleWithBottomSlotAsOther()
+            } else {
+                maxPrimaryLayoutMarginsWithTitleWithoutBottomSlot()
+            }
+        } else {
+            if (layoutSlotsPresence.isBottomSlotPresent) {
+                if (layoutSlotsPresence.isBottomSlotEdgeButton)
+                    maxPrimaryLayoutMarginsWithoutTitleWithEdgeButton()
+                else maxPrimaryLayoutMarginsWithoutTitleWithBottomSlotAsOther()
+            } else {
+                maxPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot()
+            }
+        }
+
+    // Separate all cases internally so it's easier to track from the spec.
+
+    // Bottom slot as EdgeButton. Bottom margin are not allowed to be customized in these cases.
+
+    /**
+     * Default side margins for the main slot of [primaryLayout] that should be used when there is a
+     * title slot in the layout and bottom slot is set to be [edgeButton].
+     *
+     * These values work for the majority of [Shapes], usually across round toward medium round
+     * corners.
+     */
+    internal fun MaterialScope.defaultPrimaryLayoutMarginsWithTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 7.1f / 100, end = 7.1f / 100)
+
+    /**
+     * Default side margins for the main slot of [primaryLayout] that should be used when the title
+     * slot is not present in the layout and bottom slot is set to be [edgeButton].
+     *
+     * These values work for the majority of [Shapes], usually across round toward medium round
+     * corners.
+     */
+    internal fun MaterialScope.defaultPrimaryLayoutMarginsWithoutTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 12f / 100, end = 12f / 100)
+
+    /**
+     * Min side margins for the main slot of [primaryLayout] that should be used only when the main
+     * slot contains fully rounded corners, such as [Shapes.full] to avoid clipping, and when the
+     * bottom slot is set to be [edgeButton].
+     *
+     * This can be used regardless of the title slot presence.
+     */
+    internal fun MaterialScope.minPrimaryLayoutMarginsWithEdgeButton(): Padding =
+        percentagePadding(start = 3f / 100, end = 3f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when there's title slot present and bottom slot is set to be
+     * [edgeButton].
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 5.2f / 100, end = 5.2f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when title slot is not present and bottom slot is set to be [edgeButton].
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithoutTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 7.1f / 100, end = 7.1f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when there's title slot present and bottom slot is set to be [edgeButton].
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 10f / 100, end = 10f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when title slot is not present and bottom slot is set to be [edgeButton].
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithoutTitleWithEdgeButton(): Padding =
+        percentagePadding(start = 15.5f / 100, end = 15.5f / 100)
+
+    // Bottom slot as other content. Bottom margin are not allowed to be customized in these cases.
+
+    /**
+     * Default side margins for the main slot of [primaryLayout] that should be used when the bottom
+     * slot is set to some other content besides [edgeButton].
+     *
+     * These values work for the majority of [Shapes], usually across round toward medium round
+     * corners. This can be used regardless of title slot presence.
+     */
+    internal fun MaterialScope.defaultPrimaryLayoutMarginsWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 12f / 100, end = 12f / 100)
+
+    /**
+     * Min side margins for the main slot of [primaryLayout] that should be used only when the main
+     * slot contains fully rounded corners, such as [Shapes.full] to avoid clipping, and when the
+     * bottom slot is set to some other content besides [edgeButton].
+     *
+     * This can be used regardless of the title slot presence.
+     */
+    internal fun MaterialScope.minPrimaryLayoutMarginsWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 3f / 100, end = 3f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when there's title slot present and bottom slot is set to some other
+     * content besides [edgeButton].
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithTitleWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 7.1f / 100, end = 7.1f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when title slot is not present and bottom slot is set to some other
+     * content besides [edgeButton].
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithoutTitleWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 8.3f / 100, end = 8.3f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when there's title slot present and bottom slot is set to some other content besides
+     * [edgeButton].
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithTitleWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 14f / 100, end = 14f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when title slot is not present and bottom slot is set to some other content besides
+     * [edgeButton].
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithoutTitleWithBottomSlotAsOther(): Padding =
+        percentagePadding(start = 15.5f / 100, end = 15.5f / 100)
+
+    // No bottom slot. Bottom margin are allowed to be customized in these cases.
+
+    /**
+     * Default side margins for the main slot of [primaryLayout] that should be used when title slot
+     * is present but the bottom slot is not.
+     *
+     * These values work for the majority of [Shapes], usually across round toward medium round
+     * corners.
+     */
+    internal fun MaterialScope.defaultPrimaryLayoutMarginsWithTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 10f / 100, end = 10f / 100, bottom = 16.64f / 100)
+
+    /**
+     * Default side margins for the main slot of [primaryLayout] that should be used when neither
+     * title slot or bottom slot are present.
+     *
+     * These values work for the majority of [Shapes], usually across round toward medium round
+     * corners.
+     */
+    internal fun MaterialScope.defaultPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 12f / 100, end = 12f / 100, bottom = 14f / 100)
+
+    /**
+     * Min side margins for the main slot of [primaryLayout] that should be used only when the main
+     * slot contains fully rounded corners, such as [Shapes.full] to avoid clipping, and when the
+     * bottom slot is not present.
+     *
+     * This can be used regardless of the title slot presence.
+     */
+    internal fun MaterialScope.minPrimaryLayoutMarginsWithoutBottomSlot(): Padding =
+        percentagePadding(start = 3f / 100, end = 3f / 100, bottom = 10f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when there's title slot present and bottom slot is not.
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 5.2f / 100, end = 5.2f / 100, bottom = 19.6f / 100)
+
+    /**
+     * Mid side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains fully rounded to medium round corners, for example, larger than [Shapes.medium] to
+     * avoid clipping, and when neither title slot or bottom slot are present.
+     */
+    internal fun MaterialScope.midPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 8.3f / 100, end = 8.3f / 100, bottom = 19.6f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when there's title slot present and bottom slot is not.
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 14f / 100, end = 14f / 100, bottom = 16.64f / 100)
+
+    /**
+     * Max side margins for the main slot of [primaryLayout] that should be used when the main slot
+     * contains square corners, for example, smaller than [Shapes.medium] to avoid clipping, and
+     * when neither title slot or bottom slot are present.
+     */
+    internal fun MaterialScope.maxPrimaryLayoutMarginsWithoutTitleWithoutBottomSlot(): Padding =
+        percentagePadding(start = 16.64f / 100, end = 16.64f / 100, bottom = 14f / 100)
+
+    internal fun MaterialScope.maxSideMargin() = percentageWidthToDp(16.64f / 100)
+
+    internal fun MaterialScope.maxBottomMargin() = percentageHeightToDp(19.6f / 100)
+}
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
index 7f18399..174d1af 100644
--- a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
@@ -83,6 +83,15 @@
     }
 
     @Test
+    fun avatarButton_size_default() {
+        LayoutElementAssertionsProvider(DEFAULT_AVATAR_BUTTON)
+            .onRoot()
+            .assert(hasWidth(expand()))
+            .assert(hasHeight(wrapWithMinTapTargetDimension()))
+            .assert(hasTag(ButtonDefaults.METADATA_TAG_BUTTON))
+    }
+
+    @Test
     fun compactButton_size_default() {
         LayoutElementAssertionsProvider(DEFAULT_COMPACT_BUTTON)
             .onRoot()
@@ -164,6 +173,27 @@
     }
 
     @Test
+    fun avatarButton_hasLabel_asText() {
+        LayoutElementAssertionsProvider(DEFAULT_AVATAR_BUTTON)
+            .onElement(hasText(TEXT))
+            .assertExists()
+    }
+
+    @Test
+    fun avatarButton_hasSecondaryLabel_asText() {
+        LayoutElementAssertionsProvider(DEFAULT_AVATAR_BUTTON)
+            .onElement(hasText(TEXT2))
+            .assertExists()
+    }
+
+    @Test
+    fun avatarButton_hasAvatar_asImage() {
+        LayoutElementAssertionsProvider(DEFAULT_AVATAR_BUTTON)
+            .onElement(hasImage(IMAGE_ID))
+            .assertExists()
+    }
+
+    @Test
     fun compactButton_hasLabel_asText() {
         LayoutElementAssertionsProvider(DEFAULT_COMPACT_BUTTON)
             .onElement(hasText(TEXT))
@@ -295,6 +325,17 @@
                 )
             }
 
+        private val DEFAULT_AVATAR_BUTTON =
+            materialScope(CONTEXT, DEVICE_CONFIGURATION) {
+                avatarButton(
+                    onClick = CLICKABLE,
+                    modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
+                    labelContent = { text(TEXT.layoutString) },
+                    secondaryLabelContent = { text(TEXT2.layoutString) },
+                    avatarContent = { icon(IMAGE_ID) }
+                )
+            }
+
         private val DEFAULT_COMPACT_BUTTON =
             materialScope(CONTEXT, DEVICE_CONFIGURATION) {
                 compactButton(
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/MaterialScopeTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/MaterialScopeTest.kt
index cf470ad..1f3bd04 100644
--- a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/MaterialScopeTest.kt
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/MaterialScopeTest.kt
@@ -56,7 +56,8 @@
                 defaultTextElementStyle = TextElementStyle(),
                 defaultIconStyle = IconStyle(),
                 defaultBackgroundImageStyle = BackgroundImageStyle(),
-                defaultAvatarImageStyle = AvatarImageStyle()
+                defaultAvatarImageStyle = AvatarImageStyle(),
+                layoutSlotsPresence = LayoutSlotsPresence()
             )
 
         assertThat(scopeWithDefaultTheme.deviceConfiguration).isEqualTo(DEVICE_PARAMETERS)
@@ -88,7 +89,8 @@
                 defaultTextElementStyle = TextElementStyle(),
                 defaultIconStyle = IconStyle(),
                 defaultBackgroundImageStyle = BackgroundImageStyle(),
-                defaultAvatarImageStyle = AvatarImageStyle()
+                defaultAvatarImageStyle = AvatarImageStyle(),
+                layoutSlotsPresence = LayoutSlotsPresence()
             )
 
         assertThat(materialScope.deviceConfiguration).isEqualTo(DEVICE_PARAMETERS)
@@ -124,7 +126,8 @@
                 defaultTextElementStyle = TextElementStyle(),
                 defaultIconStyle = IconStyle(),
                 defaultBackgroundImageStyle = BackgroundImageStyle(),
-                defaultAvatarImageStyle = AvatarImageStyle()
+                defaultAvatarImageStyle = AvatarImageStyle(),
+                layoutSlotsPresence = LayoutSlotsPresence()
             )
 
         assertThat(isDynamicColorSchemeEnabled(materialScope.context)).isFalse()
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/PrimaryLayoutMarginsTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/PrimaryLayoutMarginsTest.kt
new file mode 100644
index 0000000..024847d
--- /dev/null
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/PrimaryLayoutMarginsTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.wear.protolayout.material3.MaterialScopeTest.Companion.DEVICE_PARAMETERS
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.customizedPrimaryLayoutMargin
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.internal.DoNotInstrument
+
+@RunWith(AndroidJUnit4::class)
+@DoNotInstrument
+class PrimaryLayoutMarginsTest {
+    @Test
+    fun customizedMargins_horizontal_buildsPadding() {
+        val start = 0.2f
+        val end = 0.3f
+        val margins: CustomPrimaryLayoutMargins =
+            customizedPrimaryLayoutMargin(start = start, end = end) as CustomPrimaryLayoutMargins
+
+        assertThat(margins.toPadding(SCOPE).start!!.value)
+            .isEqualTo(start * DEVICE_PARAMETERS.screenWidthDp)
+        assertThat(margins.toPadding(SCOPE).end!!.value)
+            .isEqualTo(end * DEVICE_PARAMETERS.screenWidthDp)
+    }
+
+    @Test
+    fun customizedMargins_all_buildsPadding() {
+        val start = 0.2f
+        val end = 0.3f
+        val bottom = 0.4f
+        val margins: CustomPrimaryLayoutMargins =
+            customizedPrimaryLayoutMargin(start = start, end = end, bottom = bottom)
+                as CustomPrimaryLayoutMargins
+
+        assertThat(margins.toPadding(SCOPE).start!!.value)
+            .isEqualTo(start * DEVICE_PARAMETERS.screenWidthDp)
+        assertThat(margins.toPadding(SCOPE).end!!.value)
+            .isEqualTo(end * DEVICE_PARAMETERS.screenWidthDp)
+        assertThat(margins.toPadding(SCOPE).bottom!!.value)
+            .isEqualTo(bottom * DEVICE_PARAMETERS.screenWidthDp)
+    }
+
+    companion object {
+        val SCOPE =
+            MaterialScope(
+                context = getApplicationContext(),
+                deviceConfiguration = DEVICE_PARAMETERS,
+                allowDynamicTheme = true,
+                theme =
+                    MaterialTheme(
+                        colorScheme = dynamicColorScheme(context = getApplicationContext())
+                    ),
+                defaultTextElementStyle = TextElementStyle(),
+                defaultIconStyle = IconStyle(),
+                defaultBackgroundImageStyle = BackgroundImageStyle(),
+                defaultAvatarImageStyle = AvatarImageStyle(),
+                layoutSlotsPresence = LayoutSlotsPresence()
+            )
+    }
+}
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index 5ba8d45..3fff1ce 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -26,10 +26,12 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
+    id("org.jetbrains.kotlin.android")
 }
 
 dependencies {
     api(libs.jspecify)
+    api(libs.kotlinStdlib)
     annotationProcessor(libs.nullaway)
     api("androidx.annotation:annotation:1.8.1")
     api("androidx.core:core:1.7.0")
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/PropHelpers.kt b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/PropHelpers.kt
new file mode 100644
index 0000000..35ec5a4
--- /dev/null
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/PropHelpers.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      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.renderer.inflater
+
+import android.util.Log
+import androidx.wear.protolayout.proto.ColorProto.ColorProp
+import androidx.wear.protolayout.proto.DimensionProto.DegreesProp
+import androidx.wear.protolayout.proto.DimensionProto.DpProp
+import androidx.wear.protolayout.proto.TypesProto.BoolProp
+import androidx.wear.protolayout.proto.TypesProto.FloatProp
+import androidx.wear.protolayout.proto.TypesProto.StringProp
+import androidx.wear.protolayout.renderer.dynamicdata.ProtoLayoutDynamicDataPipeline.PipelineMaker
+import java.util.Locale
+import java.util.Optional
+import java.util.function.Consumer
+
+/** Helpers for handling Prop classes' static and dynamic values. */
+internal object PropHelpers {
+    const val TAG = "ProtolayoutPropHelpers"
+
+    /** Handles a StringProp. */
+    @JvmStatic
+    fun handleProp(
+        stringProp: StringProp,
+        locale: Locale,
+        consumer: Consumer<String>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (stringProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker
+                    .get()
+                    .addPipelineFor(
+                        stringProp.dynamicValue,
+                        stringProp.value,
+                        locale,
+                        posId,
+                        consumer
+                    )
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                consumer.accept(stringProp.value)
+            }
+        } else {
+            consumer.accept(stringProp.value)
+        }
+    }
+
+    /** Handles a DegreesProp. */
+    @JvmStatic
+    fun handleProp(
+        degreesProp: DegreesProp,
+        consumer: Consumer<Float>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (degreesProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker.get().addPipelineFor(degreesProp, degreesProp.value, posId, consumer)
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                consumer.accept(degreesProp.value)
+            }
+        } else {
+            consumer.accept(degreesProp.value)
+        }
+    }
+
+    /** Handles a DpProp. */
+    @JvmStatic
+    fun handleProp(
+        dpProp: DpProp,
+        consumer: Consumer<Float>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) = handleProp(dpProp, consumer, consumer, posId, pipelineMaker)
+
+    /** Handles a DpProp. */
+    @JvmStatic
+    fun handleProp(
+        dpProp: DpProp,
+        staticValueConsumer: Consumer<Float>,
+        dynamicValueConsumer: Consumer<Float>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (dpProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker
+                    .get()
+                    .addPipelineFor(dpProp, dpProp.value, posId, dynamicValueConsumer)
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                staticValueConsumer.accept(dpProp.value)
+            }
+        } else {
+            staticValueConsumer.accept(dpProp.value)
+        }
+    }
+
+    /** Handles a ColorProp. */
+    @JvmStatic
+    fun handleProp(
+        colorProp: ColorProp,
+        consumer: Consumer<Int>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (colorProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker.get().addPipelineFor(colorProp, colorProp.argb, posId, consumer)
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                consumer.accept(colorProp.argb)
+            }
+        } else {
+            consumer.accept(colorProp.argb)
+        }
+    }
+
+    /** Handles a BoolProp. */
+    @JvmStatic
+    fun handleProp(
+        boolProp: BoolProp,
+        consumer: Consumer<Boolean>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (boolProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker.get().addPipelineFor(boolProp, boolProp.value, posId, consumer)
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                consumer.accept(boolProp.value)
+            }
+        } else {
+            consumer.accept(boolProp.value)
+        }
+    }
+
+    /** Handles a FloatProp. */
+    @JvmStatic
+    fun handleProp(
+        floatProp: FloatProp,
+        consumer: Consumer<Float>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) = handleProp(floatProp, consumer, consumer, posId, pipelineMaker)
+
+    /** Handles a FloatProp. */
+    @JvmStatic
+    fun handleProp(
+        floatProp: FloatProp,
+        staticValueConsumer: Consumer<Float>,
+        dynamicValueconsumer: Consumer<Float>,
+        posId: String,
+        pipelineMaker: Optional<PipelineMaker>,
+    ) {
+        if (floatProp.hasDynamicValue() && pipelineMaker.isPresent()) {
+            try {
+                pipelineMaker
+                    .get()
+                    .addPipelineFor(
+                        floatProp.dynamicValue,
+                        floatProp.value,
+                        posId,
+                        dynamicValueconsumer
+                    )
+            } catch (ex: RuntimeException) {
+                Log.e(TAG, "Error building pipeline", ex)
+                staticValueConsumer.accept(floatProp.value)
+            }
+        } else {
+            staticValueConsumer.accept(floatProp.value)
+        }
+    }
+}
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
index 012a095..41612f8 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
@@ -26,6 +26,7 @@
 import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.FIRST_CHILD_INDEX;
 import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.ROOT_NODE_ID;
 import static androidx.wear.protolayout.renderer.common.ProtoLayoutDiffer.getParentNodePosId;
+import static androidx.wear.protolayout.renderer.inflater.PropHelpers.handleProp;
 
 import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
 import static com.google.common.util.concurrent.Futures.immediateFuture;
@@ -105,7 +106,6 @@
 import androidx.wear.protolayout.proto.AlignmentProto.TextAlignment;
 import androidx.wear.protolayout.proto.AlignmentProto.VerticalAlignment;
 import androidx.wear.protolayout.proto.AlignmentProto.VerticalAlignmentProp;
-import androidx.wear.protolayout.proto.ColorProto.ColorProp;
 import androidx.wear.protolayout.proto.DimensionProto.AngularDimension;
 import androidx.wear.protolayout.proto.DimensionProto.ArcLineLength;
 import androidx.wear.protolayout.proto.DimensionProto.ContainerDimension;
@@ -2829,6 +2829,7 @@
 
         handleProp(
                 text.getText(),
+                mUiContext.getResources().getConfiguration().getLocales().get(0),
                 t -> {
                     // Underlines are applied using a Spannable here, rather than setting paint bits
                     // (or
@@ -4238,152 +4239,6 @@
     }
 
     /**
-     * Either yield the constant value stored in stringProp, or register for updates if it is
-     * dynamic property.
-     *
-     * <p>If both are set, this routine will yield the constant value if and only if this renderer
-     * has a dynamic pipeline (i.e. {code mDataPipeline} is non-null), otherwise it will only
-     * subscribe for dynamic updates. If the dynamic pipeline ever yields an invalid value (via
-     * {@code onStateInvalid}), then stringProp's static valid will be used instead.
-     */
-    private void handleProp(
-            StringProp stringProp,
-            Consumer<String> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (stringProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker
-                        .get()
-                        .addPipelineFor(
-                                stringProp.getDynamicValue(),
-                                stringProp.getValue(),
-                                mUiContext.getResources().getConfiguration().getLocales().get(0),
-                                posId,
-                                consumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                consumer.accept(stringProp.getValue());
-            }
-        } else {
-            consumer.accept(stringProp.getValue());
-        }
-    }
-
-    private void handleProp(
-            DegreesProp degreesProp,
-            Consumer<Float> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (degreesProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker
-                        .get()
-                        .addPipelineFor(degreesProp, degreesProp.getValue(), posId, consumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                consumer.accept(degreesProp.getValue());
-            }
-        } else {
-            consumer.accept(degreesProp.getValue());
-        }
-    }
-
-    private void handleProp(
-            DpProp dpProp,
-            Consumer<Float> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        handleProp(dpProp, consumer, consumer, posId, pipelineMaker);
-    }
-
-    private void handleProp(
-            DpProp dpProp,
-            Consumer<Float> staticValueConsumer,
-            Consumer<Float> dynamicValueConsumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (dpProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker
-                        .get()
-                        .addPipelineFor(dpProp, dpProp.getValue(), posId, dynamicValueConsumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                staticValueConsumer.accept(dpProp.getValue());
-            }
-        } else {
-            staticValueConsumer.accept(dpProp.getValue());
-        }
-    }
-
-    private void handleProp(
-            ColorProp colorProp,
-            Consumer<Integer> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (colorProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker.get().addPipelineFor(colorProp, colorProp.getArgb(), posId, consumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                consumer.accept(colorProp.getArgb());
-            }
-        } else {
-            consumer.accept(colorProp.getArgb());
-        }
-    }
-
-    private void handleProp(
-            BoolProp boolProp,
-            Consumer<Boolean> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (boolProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker.get().addPipelineFor(boolProp, boolProp.getValue(), posId, consumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                consumer.accept(boolProp.getValue());
-            }
-        } else {
-            consumer.accept(boolProp.getValue());
-        }
-    }
-
-    private void handleProp(
-            FloatProp floatProp,
-            Consumer<Float> consumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        handleProp(floatProp, consumer, consumer, posId, pipelineMaker);
-    }
-
-    private void handleProp(
-            FloatProp floatProp,
-            Consumer<Float> staticValueConsumer,
-            Consumer<Float> dynamicValueconsumer,
-            String posId,
-            Optional<PipelineMaker> pipelineMaker) {
-        if (floatProp.hasDynamicValue() && pipelineMaker.isPresent()) {
-            try {
-                pipelineMaker
-                        .get()
-                        .addPipelineFor(
-                                floatProp.getDynamicValue(),
-                                floatProp.getValue(),
-                                posId,
-                                dynamicValueconsumer);
-            } catch (RuntimeException ex) {
-                Log.e(TAG, "Error building pipeline", ex);
-                staticValueConsumer.accept(floatProp.getValue());
-            }
-        } else {
-            staticValueConsumer.accept(floatProp.getValue());
-        }
-    }
-
-    /**
      * Resolves the value for layout to be used in a Size Wrapper for elements containing dynamic
      * values. Returns null if no size wrapper is needed.
      */
@@ -4959,6 +4814,7 @@
         if (semantics.hasContentDescription()) {
             handleProp(
                     semantics.getContentDescription(),
+                    mUiContext.getResources().getConfiguration().getLocales().get(0),
                     view::setContentDescription,
                     posId,
                     pipelineMaker);
@@ -4970,6 +4826,7 @@
         if (semantics.hasStateDescription()) {
             handleProp(
                     semantics.getStateDescription(),
+                    mUiContext.getResources().getConfiguration().getLocales().get(0),
                     (state) -> ViewCompat.setStateDescription(view, state),
                     posId,
                     pipelineMaker);
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index da4e766..4fb6ee7 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1436,11 +1436,11 @@
   public final class TriggerBuilders {
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnConditionMetTrigger(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnLoadTrigger();
-    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleOnceTrigger();
+    method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleOnceTrigger();
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleTrigger();
   }
 
-  @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class TriggerBuilders.OnVisibleOnceTrigger implements androidx.wear.protolayout.TriggerBuilders.Trigger {
+  @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class TriggerBuilders.OnVisibleOnceTrigger implements androidx.wear.protolayout.TriggerBuilders.Trigger {
   }
 
   public static final class TriggerBuilders.OnVisibleOnceTrigger.Builder {
@@ -1564,17 +1564,17 @@
   }
 
   public interface LayoutModifier {
-    method public <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
     method public default infix androidx.wear.protolayout.modifiers.LayoutModifier then(androidx.wear.protolayout.modifiers.LayoutModifier other);
     field public static final androidx.wear.protolayout.modifiers.LayoutModifier.Companion Companion;
   }
 
   public static final class LayoutModifier.Companion implements androidx.wear.protolayout.modifiers.LayoutModifier {
-    method public <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
   }
 
   public static interface LayoutModifier.Element extends androidx.wear.protolayout.modifiers.LayoutModifier {
-    method public default <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public default <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
   }
 
   public final class ModifierAppliersKt {
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index da4e766..4fb6ee7 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1436,11 +1436,11 @@
   public final class TriggerBuilders {
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnConditionMetTrigger(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnLoadTrigger();
-    method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleOnceTrigger();
+    method @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleOnceTrigger();
     method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static androidx.wear.protolayout.TriggerBuilders.Trigger createOnVisibleTrigger();
   }
 
-  @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class TriggerBuilders.OnVisibleOnceTrigger implements androidx.wear.protolayout.TriggerBuilders.Trigger {
+  @SuppressCompatibility @androidx.wear.protolayout.expression.ProtoLayoutExperimental @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class TriggerBuilders.OnVisibleOnceTrigger implements androidx.wear.protolayout.TriggerBuilders.Trigger {
   }
 
   public static final class TriggerBuilders.OnVisibleOnceTrigger.Builder {
@@ -1564,17 +1564,17 @@
   }
 
   public interface LayoutModifier {
-    method public <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
     method public default infix androidx.wear.protolayout.modifiers.LayoutModifier then(androidx.wear.protolayout.modifiers.LayoutModifier other);
     field public static final androidx.wear.protolayout.modifiers.LayoutModifier.Companion Companion;
   }
 
   public static final class LayoutModifier.Companion implements androidx.wear.protolayout.modifiers.LayoutModifier {
-    method public <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
   }
 
   public static interface LayoutModifier.Element extends androidx.wear.protolayout.modifiers.LayoutModifier {
-    method public default <R> R foldIn(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
+    method public default <R> R foldRight(R initial, kotlin.jvm.functions.Function2<? super R,? super androidx.wear.protolayout.modifiers.LayoutModifier.Element,? extends R> operation);
   }
 
   public final class ModifierAppliersKt {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
index a51c996..99e14b8 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ResourceBuilders.java
@@ -521,6 +521,7 @@
         }
 
         /** Gets the trigger to start the animation. */
+        @OptIn(markerClass = ProtoLayoutExperimental.class)
         public @Nullable Trigger getStartTrigger() {
             if (mImpl.hasStartTrigger()) {
                 return TriggerBuilders.triggerFromProto(mImpl.getStartTrigger());
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
index d05a53c..1c7a82a 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TriggerBuilders.java
@@ -23,6 +23,7 @@
 import androidx.wear.protolayout.expression.DynamicBuilders;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
 import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
 import androidx.wear.protolayout.expression.RequiresSchemaVersion;
 import androidx.wear.protolayout.proto.TriggerProto;
 
@@ -66,6 +67,7 @@
      * that the layout becomes visible.
      */
     @RequiresSchemaVersion(major = 1, minor = 200)
+    @ProtoLayoutExperimental
     public static @NonNull Trigger createOnVisibleOnceTrigger() {
         return new OnVisibleOnceTrigger.Builder().build();
     }
@@ -138,6 +140,7 @@
      * the first time.
      */
     @RequiresSchemaVersion(major = 1, minor = 200)
+    @ProtoLayoutExperimental
     public static final class OnVisibleOnceTrigger implements Trigger {
         private final TriggerProto.OnVisibleOnceTrigger mImpl;
         private final @Nullable Fingerprint mFingerprint;
@@ -377,6 +380,7 @@
 
     /** Creates a new wrapper instance from the proto. */
     @RestrictTo(Scope.LIBRARY_GROUP)
+    @ProtoLayoutExperimental
     public static @NonNull Trigger triggerFromProto(
             TriggerProto.@NonNull Trigger proto, @Nullable Fingerprint fingerprint) {
         if (proto.hasOnVisibleTrigger()) {
@@ -394,6 +398,7 @@
         throw new IllegalStateException("Proto was not a recognised instance of Trigger");
     }
 
+    @ProtoLayoutExperimental
     static @NonNull Trigger triggerFromProto(TriggerProto.@NonNull Trigger proto) {
         return triggerFromProto(proto, null);
     }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Background.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Background.kt
index 322861d..89df3a3 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Background.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Background.kt
@@ -115,7 +115,7 @@
 ): LayoutModifier = this then BaseCornerElement(bottomRightRadius = cornerRadius(x, y))
 
 internal class BaseBackgroundElement(val color: LayoutColor) : LayoutModifier.Element {
-    fun foldIn(initial: Background.Builder?): Background.Builder =
+    fun mergeTo(initial: Background.Builder?): Background.Builder =
         (initial ?: Background.Builder()).setColor(color.prop)
 }
 
@@ -127,7 +127,7 @@
     @RequiresSchemaVersion(major = 1, minor = 400) val bottomRightRadius: CornerRadius? = null
 ) : LayoutModifier.Element {
     @SuppressLint("ProtoLayoutMinSchema")
-    fun foldIn(initial: Corner.Builder?): Corner.Builder =
+    fun mergeTo(initial: Corner.Builder?): Corner.Builder =
         (initial ?: Corner.Builder()).apply {
             cornerRadiusDp?.let { setRadius(cornerRadiusDp.dp) }
             topLeftRadius?.let { setTopLeftRadius(cornerRadius(it.x.value, it.y.value)) }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Border.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Border.kt
index d3fca75..47e1ec1 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Border.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Border.kt
@@ -33,6 +33,6 @@
 
 internal class BaseBorderElement(@Dimension(DP) val width: Float, val color: LayoutColor) :
     LayoutModifier.Element {
-    fun foldIn(initial: Border.Builder?): Border.Builder =
+    fun mergeTo(initial: Border.Builder?): Border.Builder =
         (initial ?: Border.Builder()).setWidth(width.dp).setColor(color.prop)
 }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Clickable.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Clickable.kt
index da4d74f..a807b15 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Clickable.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Clickable.kt
@@ -122,7 +122,7 @@
     @Dimension(DP) val minClickableHeight: Float = Float.NaN,
 ) : LayoutModifier.Element {
     @SuppressLint("ProtoLayoutMinSchema")
-    fun foldIn(initial: Clickable.Builder?): Clickable.Builder =
+    fun mergeTo(initial: Clickable.Builder?): Clickable.Builder =
         (initial ?: Clickable.Builder()).apply {
             if (!id.isNullOrEmpty()) setId(id)
             action?.let { setOnClick(it) }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/LayoutModifier.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/LayoutModifier.kt
index 74657a0..468ef56 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/LayoutModifier.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/LayoutModifier.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.protolayout.modifiers
 
+import androidx.wear.protolayout.modifiers.LayoutModifier.Element
 import java.util.Objects
 
 /**
@@ -28,14 +29,12 @@
 interface LayoutModifier {
     /**
      * Accumulates a value starting with [initial] and applying [operation] to the current value and
-     * each element from outside in.
+     * each element from left to right.
      *
-     * Elements wrap one another in a chain from left to right; an [Element] that appears to the
-     * left of another in a `+` expression or in [operation]'s parameter order affects all of the
-     * elements that appear after it. [foldIn] may be used to accumulate a value starting from the
-     * parent or head of the modifier chain to the final wrapped child.
+     * [foldRight] may be used to accumulate a value starting from the head of the modifier chain to
+     * the final modifier element.
      */
-    fun <R> foldIn(initial: R, operation: (R, Element) -> R): R
+    fun <R> foldRight(initial: R, operation: (R, Element) -> R): R
 
     /**
      * Concatenates this modifier with another.
@@ -47,7 +46,7 @@
 
     /** A single element contained within a [LayoutModifier] chain. */
     interface Element : LayoutModifier {
-        override fun <R> foldIn(initial: R, operation: (R, Element) -> R): R =
+        override fun <R> foldRight(initial: R, operation: (R, Element) -> R): R =
             operation(initial, this)
     }
 
@@ -58,7 +57,7 @@
      */
     companion object : LayoutModifier {
         @Suppress("MissingJvmstatic")
-        override fun <R> foldIn(initial: R, operation: (R, Element) -> R): R = initial
+        override fun <R> foldRight(initial: R, operation: (R, Element) -> R): R = initial
 
         @Suppress("MissingJvmstatic")
         override infix fun then(other: LayoutModifier): LayoutModifier = other
@@ -68,24 +67,24 @@
 }
 
 /**
- * A node in a [LayoutModifier] chain. A CombinedModifier always contains at least two elements; a
- * * Modifier [outer] that wraps around the Modifier [inner].
+ * A node in a [LayoutModifier] chain. A [CombinedLayoutModifier] always contains at least two
+ * elements.
  */
 internal class CombinedLayoutModifier(
-    private val outer: LayoutModifier,
-    private val inner: LayoutModifier
+    private val left: LayoutModifier,
+    private val right: LayoutModifier
 ) : LayoutModifier {
-    override fun <R> foldIn(initial: R, operation: (R, LayoutModifier.Element) -> R): R =
-        inner.foldIn(outer.foldIn(initial, operation), operation)
+    override fun <R> foldRight(initial: R, operation: (R, Element) -> R): R =
+        right.foldRight(left.foldRight(initial, operation), operation)
 
     override fun equals(other: Any?): Boolean =
-        other is CombinedLayoutModifier && outer == other.outer && inner == other.inner
+        other is CombinedLayoutModifier && left == other.left && right == other.right
 
-    override fun hashCode(): Int = Objects.hash(outer, inner)
+    override fun hashCode(): Int = Objects.hash(left, right)
 
     override fun toString(): String =
         "[" +
-            foldIn("") { acc, element ->
+            foldRight("") { acc, element ->
                 if (acc.isEmpty()) element.toString() else "$acc, $element"
             } +
             "]"
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Metadata.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Metadata.kt
index 9c0f8ca..7fb3fb2 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Metadata.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Metadata.kt
@@ -35,6 +35,6 @@
 fun LayoutModifier.tag(tag: String): LayoutModifier = tag(tag.toByteArray())
 
 internal class BaseMetadataElement(val tagData: ByteArray) : LayoutModifier.Element {
-    fun foldIn(initial: ElementMetadata.Builder?): ElementMetadata.Builder =
+    fun mergeTo(initial: ElementMetadata.Builder?): ElementMetadata.Builder =
         (initial ?: ElementMetadata.Builder()).setTagData(tagData)
 }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/ModifierAppliers.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/ModifierAppliers.kt
index aee3599..af956d0 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/ModifierAppliers.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/ModifierAppliers.kt
@@ -44,17 +44,17 @@
     var visible: BoolProp.Builder? = null
     var opacity: FloatProp.Builder? = null
 
-    this.foldIn(Unit) { _, e ->
+    this.foldRight(Unit) { _, e ->
         when (e) {
-            is BaseSemanticElement -> semantics = e.foldIn(semantics)
-            is BaseBackgroundElement -> background = e.foldIn(background)
-            is BaseCornerElement -> corners = e.foldIn(corners)
-            is BaseClickableElement -> clickable = e.foldIn(clickable)
-            is BasePaddingElement -> padding = e.foldIn(padding)
-            is BaseMetadataElement -> metadata = e.foldIn(metadata)
-            is BaseBorderElement -> border = e.foldIn(border)
-            is BaseVisibilityElement -> visible = e.foldIn(visible)
-            is BaseOpacityElement -> opacity = e.foldIn(opacity)
+            is BaseSemanticElement -> semantics = e.mergeTo(semantics)
+            is BaseBackgroundElement -> background = e.mergeTo(background)
+            is BaseCornerElement -> corners = e.mergeTo(corners)
+            is BaseClickableElement -> clickable = e.mergeTo(clickable)
+            is BasePaddingElement -> padding = e.mergeTo(padding)
+            is BaseMetadataElement -> metadata = e.mergeTo(metadata)
+            is BaseBorderElement -> border = e.mergeTo(border)
+            is BaseVisibilityElement -> visible = e.mergeTo(visible)
+            is BaseOpacityElement -> opacity = e.mergeTo(opacity)
         }
     }
 
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Opacity.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Opacity.kt
index eeafb8f9..e8d6f3d 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Opacity.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Opacity.kt
@@ -42,7 +42,7 @@
 internal class BaseOpacityElement(val staticValue: Float, val dynamicValue: DynamicFloat? = null) :
     LayoutModifier.Element {
     @SuppressLint("ProtoLayoutMinSchema")
-    fun foldIn(initial: FloatProp.Builder?): FloatProp.Builder =
+    fun mergeTo(initial: FloatProp.Builder?): FloatProp.Builder =
         (initial ?: FloatProp.Builder(staticValue)).apply {
             dynamicValue?.let { setDynamicValue(it) }
         }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Padding.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Padding.kt
index 050b8ce..af7df74 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Padding.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Padding.kt
@@ -139,7 +139,7 @@
     val rtlAware: Boolean = true
 ) : LayoutModifier.Element {
 
-    fun foldIn(initial: Padding.Builder?): Padding.Builder =
+    fun mergeTo(initial: Padding.Builder?): Padding.Builder =
         (initial ?: Padding.Builder()).apply {
             if (!start.isNaN()) {
                 setStart(start.dp)
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Semantics.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Semantics.kt
index d77f5e3..7d1b332 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Semantics.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Semantics.kt
@@ -58,7 +58,7 @@
     @SemanticsRole val semanticsRole: Int = SEMANTICS_ROLE_NONE
 ) : LayoutModifier.Element {
     @SuppressLint("ProtoLayoutMinSchema")
-    fun foldIn(initial: Semantics.Builder?): Semantics.Builder =
+    fun mergeTo(initial: Semantics.Builder?): Semantics.Builder =
         (initial ?: Semantics.Builder()).apply {
             contentDescription?.let { setContentDescription(it) }
             if (semanticsRole != SEMANTICS_ROLE_NONE) {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Visibility.kt b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Visibility.kt
index b7eabd7..cb1596ab3 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Visibility.kt
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/modifiers/Visibility.kt
@@ -46,7 +46,7 @@
     val dynamicVisibility: DynamicBool? = null
 ) : LayoutModifier.Element {
     @SuppressLint("ProtoLayoutMinSchema")
-    fun foldIn(initial: BoolProp.Builder?): BoolProp.Builder =
+    fun mergeTo(initial: BoolProp.Builder?): BoolProp.Builder =
         (initial ?: BoolProp.Builder(visibility)).apply {
             dynamicVisibility?.let { setDynamicValue(it) }
         }
diff --git a/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt b/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
index 183279b..d370263 100644
--- a/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
+++ b/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
@@ -28,6 +28,7 @@
 import androidx.wear.protolayout.TimelineBuilders
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
 import androidx.wear.protolayout.expression.VersionBuilders.VersionInfo
+import androidx.wear.protolayout.material3.AvatarButtonStyle.Companion.largeAvatarButtonStyle
 import androidx.wear.protolayout.material3.ButtonDefaults.filledVariantButtonColors
 import androidx.wear.protolayout.material3.CardColors
 import androidx.wear.protolayout.material3.CardDefaults.filledTonalCardColors
@@ -36,8 +37,10 @@
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.extraLargeDataCardStyle
 import androidx.wear.protolayout.material3.DataCardStyle.Companion.smallCompactDataCardStyle
 import androidx.wear.protolayout.material3.MaterialScope
+import androidx.wear.protolayout.material3.PrimaryLayoutMargins.Companion.MAX_PRIMARY_LAYOUT_MARGIN
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.smallTextButtonStyle
 import androidx.wear.protolayout.material3.appCard
+import androidx.wear.protolayout.material3.avatarButton
 import androidx.wear.protolayout.material3.avatarImage
 import androidx.wear.protolayout.material3.button
 import androidx.wear.protolayout.material3.buttonGroup
@@ -126,7 +129,8 @@
 ): LayoutElementBuilders.LayoutElement =
     materialScope(context = context, deviceConfiguration = requestParams.deviceConfiguration) {
         primaryLayout(
-            mainSlot = { graphicDataCardSample() },
+            mainSlot = { oneSlotButtons() },
+            margins = MAX_PRIMARY_LAYOUT_MARGIN,
             bottomSlot = {
                 textEdgeButton(
                     onClick = clickable(),
@@ -138,6 +142,17 @@
         )
     }
 
+private fun MaterialScope.avatarButtonSample() =
+    avatarButton(
+        onClick = clickable(),
+        modifier = LayoutModifier.contentDescription("Avatar button"),
+        avatarContent = { avatarImage(AVATAR_ID) },
+        style = largeAvatarButtonStyle(),
+        horizontalAlignment = LayoutElementBuilders.HORIZONTAL_ALIGN_END,
+        labelContent = { text("Primary label overflowing".layoutString) },
+        secondaryLabelContent = { text("Secondary label overflowing".layoutString) },
+    )
+
 private fun MaterialScope.pillShapeButton() =
     button(
         onClick = clickable(),
diff --git a/webkit/webkit/api/1.13.0-beta01.txt b/webkit/webkit/api/1.13.0-beta01.txt
new file mode 100644
index 0000000..4a0366f
--- /dev/null
+++ b/webkit/webkit/api/1.13.0-beta01.txt
@@ -0,0 +1,570 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public interface BlockingStartUpLocation {
+    method public String getStackInformation();
+  }
+
+  @AnyThread public class CookieManagerCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
+  }
+
+  public final class DropDataContentProvider extends android.content.ContentProvider {
+    ctor public DropDataContentProvider();
+    method public int delete(android.net.Uri, String?, String![]?);
+    method public String? getType(android.net.Uri);
+    method public android.net.Uri? insert(android.net.Uri, android.content.ContentValues?);
+    method public boolean onCreate();
+    method public android.database.Cursor? query(android.net.Uri, String![]?, String?, String![]?, String?);
+    method public int update(android.net.Uri, android.content.ContentValues?, String?, String![]?);
+  }
+
+  @UiThread public abstract class JavaScriptReplyProxy {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class NoVarySearchHeader {
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader alwaysVaryData();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader neverVaryData();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader neverVaryExcept(boolean, java.util.List<java.lang.String!>);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader varyExcept(boolean, java.util.List<java.lang.String!>);
+    field public final java.util.List<java.lang.String!> consideredQueryParameters;
+    field public final boolean ignoreDifferencesInParameters;
+    field public final java.util.List<java.lang.String!> ignoredQueryParameters;
+    field public final boolean varyOnKeyOrder;
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public interface OutcomeReceiverCompat<T, E extends java.lang.Throwable> {
+    method public default void onError(E);
+    method public void onResult(T!);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class PrefetchException extends java.lang.Exception {
+    ctor public PrefetchException();
+    ctor public PrefetchException(String);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class PrefetchNetworkException extends androidx.webkit.PrefetchException {
+    ctor public PrefetchNetworkException();
+    ctor public PrefetchNetworkException(int);
+    ctor public PrefetchNetworkException(String);
+    ctor public PrefetchNetworkException(String, int);
+    field public static final int NO_HTTP_RESPONSE_STATUS_CODE = 0; // 0x0
+    field public final int httpResponseStatusCode;
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public class PrerenderException extends java.lang.Exception {
+    ctor public PrerenderException(String, Throwable?);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public interface PrerenderOperationCallback {
+    method public void onError(androidx.webkit.PrerenderException);
+    method public void onPrerenderActivated();
+  }
+
+  public class ProcessGlobalConfig {
+    ctor public ProcessGlobalConfig();
+    method public static void apply(androidx.webkit.ProcessGlobalConfig);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setPartitionedCookiesEnabled(android.content.Context, boolean);
+  }
+
+  public interface Profile {
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void clearPrefetchAsync(String, java.util.concurrent.Executor, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void prefetchUrlAsync(String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void prefetchUrlAsync(String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.SpeculativeLoadingParameters, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING_CONFIG, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void setSpeculativeLoadingConfig(androidx.webkit.SpeculativeLoadingConfig);
+    field public static final String DEFAULT_PROFILE_NAME = "Default";
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface Profile.ExperimentalUrlPrefetch {
+  }
+
+  @UiThread public interface ProfileStore {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+  }
+
+  public final class ProxyConfig {
+    method public java.util.List<java.lang.String!> getBypassRules();
+    method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
+    method public boolean isReverseBypassEnabled();
+    field public static final String MATCH_ALL_SCHEMES = "*";
+    field public static final String MATCH_HTTP = "http";
+    field public static final String MATCH_HTTPS = "https";
+  }
+
+  public static final class ProxyConfig.Builder {
+    ctor public ProxyConfig.Builder();
+    ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
+    method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
+    method public androidx.webkit.ProxyConfig.Builder addDirect();
+    method public androidx.webkit.ProxyConfig.Builder addDirect(String);
+    method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
+    method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
+    method public androidx.webkit.ProxyConfig build();
+    method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
+    method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
+  }
+
+  public static final class ProxyConfig.ProxyRule {
+    method public String getSchemeFilter();
+    method public String getUrl();
+  }
+
+  @AnyThread public abstract class ProxyController {
+    method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
+    method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
+  }
+
+  public abstract class SafeBrowsingResponseCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
+  }
+
+  public interface ScriptHandler {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public void remove();
+  }
+
+  public abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  @AnyThread public abstract class ServiceWorkerControllerCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+    method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
+  }
+
+  @AnyThread public abstract class ServiceWorkerWebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class SpeculativeLoadingConfig {
+    method @IntRange(from=1, to=androidx.webkit.SpeculativeLoadingConfig.ABSOLUTE_MAX_PREFETCHES) public int getMaxPrefetches();
+    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getPrefetchTtlSeconds();
+    field public static final int ABSOLUTE_MAX_PREFETCHES = 20; // 0x14
+    field public static final int DEFAULT_MAX_PREFETCHES = 10; // 0xa
+    field public static final int DEFAULT_TTL_SECS = 60; // 0x3c
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final class SpeculativeLoadingConfig.Builder {
+    ctor public SpeculativeLoadingConfig.Builder();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingConfig build();
+    method public androidx.webkit.SpeculativeLoadingConfig.Builder setMaxPrefetches(@IntRange(from=1, to=androidx.webkit.SpeculativeLoadingConfig.ABSOLUTE_MAX_PREFETCHES) int);
+    method public androidx.webkit.SpeculativeLoadingConfig.Builder setPrefetchTtlSeconds(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+  }
+
+  @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.Profile.ExperimentalUrlPrefetch public final class SpeculativeLoadingParameters {
+    method public java.util.Map<java.lang.String!,java.lang.String!> getAdditionalHeaders();
+    method public androidx.webkit.NoVarySearchHeader? getExpectedNoVarySearchData();
+    method public boolean isJavaScriptEnabled();
+  }
+
+  public static final class SpeculativeLoadingParameters.Builder {
+    ctor public SpeculativeLoadingParameters.Builder();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder addAdditionalHeader(String, String);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder addAdditionalHeaders(java.util.Map<java.lang.String!,java.lang.String!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters build();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder setExpectedNoVarySearchData(androidx.webkit.NoVarySearchHeader);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder setJavaScriptEnabled(boolean);
+  }
+
+  public class TracingConfig {
+    method public java.util.List<java.lang.String!> getCustomIncludedCategories();
+    method public int getPredefinedCategories();
+    method public int getTracingMode();
+    field public static final int CATEGORIES_ALL = 1; // 0x1
+    field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+    field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+    field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+    field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+    field public static final int CATEGORIES_NONE = 0; // 0x0
+    field public static final int CATEGORIES_RENDERING = 16; // 0x10
+    field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
+    field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+    field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+  }
+
+  public static class TracingConfig.Builder {
+    ctor public TracingConfig.Builder();
+    method public androidx.webkit.TracingConfig.Builder addCategories(int...);
+    method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
+    method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
+    method public androidx.webkit.TracingConfig build();
+    method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
+  }
+
+  @AnyThread public abstract class TracingController {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
+    method public abstract boolean isTracing();
+    method public abstract void start(androidx.webkit.TracingConfig);
+    method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
+  }
+
+  public final class URLUtilCompat {
+    method public static String? getFilenameFromContentDisposition(String);
+    method public static String guessFileName(String, String?, String?);
+  }
+
+  public final class UserAgentMetadata {
+    method public String? getArchitecture();
+    method public int getBitness();
+    method public java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!> getBrandVersionList();
+    method public String? getFullVersion();
+    method public String? getModel();
+    method public String? getPlatform();
+    method public String? getPlatformVersion();
+    method public boolean isMobile();
+    method public boolean isWow64();
+    field public static final int BITNESS_DEFAULT = 0; // 0x0
+  }
+
+  public static final class UserAgentMetadata.BrandVersion {
+    method public String getBrand();
+    method public String getFullVersion();
+    method public String getMajorVersion();
+  }
+
+  public static final class UserAgentMetadata.BrandVersion.Builder {
+    ctor public UserAgentMetadata.BrandVersion.Builder();
+    ctor public UserAgentMetadata.BrandVersion.Builder(androidx.webkit.UserAgentMetadata.BrandVersion);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion build();
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setBrand(String);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setFullVersion(String);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setMajorVersion(String);
+  }
+
+  public static final class UserAgentMetadata.Builder {
+    ctor public UserAgentMetadata.Builder();
+    ctor public UserAgentMetadata.Builder(androidx.webkit.UserAgentMetadata);
+    method public androidx.webkit.UserAgentMetadata build();
+    method public androidx.webkit.UserAgentMetadata.Builder setArchitecture(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setBitness(int);
+    method public androidx.webkit.UserAgentMetadata.Builder setBrandVersionList(java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!>);
+    method public androidx.webkit.UserAgentMetadata.Builder setFullVersion(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setMobile(boolean);
+    method public androidx.webkit.UserAgentMetadata.Builder setModel(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setPlatform(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setPlatformVersion(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setWow64(boolean);
+  }
+
+  public class WebMessageCompat {
+    ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+    ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
+    ctor public WebMessageCompat(String?);
+    ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+    method public byte[] getArrayBuffer();
+    method public String? getData();
+    method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+    method public int getType();
+    field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+    field public static final int TYPE_STRING = 0; // 0x0
+  }
+
+  @AnyThread public abstract class WebMessagePortCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+  }
+
+  public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
+    ctor public WebMessagePortCompat.WebMessageCallbackCompat();
+    method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
+  }
+
+  public abstract class WebResourceErrorCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
+  }
+
+  public class WebResourceRequestCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
+  }
+
+  public class WebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.BACK_FORWARD_CACHE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalBackForwardCache public static boolean getBackForwardCacheEnabled(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static int getSpeculativeLoadingStatus(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_AUTHENTICATION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static int getWebAuthenticationSupport(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewMediaIntegrityApiStatusConfig getWebViewMediaIntegrityApiStatus(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.BACK_FORWARD_CACHE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalBackForwardCache public static void setBackForwardCacheEnabled(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static void setSpeculativeLoadingStatus(android.webkit.WebSettings, @SuppressCompatibility int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_AUTHENTICATION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebAuthenticationSupport(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewMediaIntegrityApiStatus(android.webkit.WebSettings, androidx.webkit.WebViewMediaIntegrityApiStatusConfig);
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+    field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+    field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
+    field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
+    field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
+    field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
+    field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
+    field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
+    field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
+    field @SuppressCompatibility @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static final int SPECULATIVE_LOADING_DISABLED = 0; // 0x0
+    field @SuppressCompatibility @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static final int SPECULATIVE_LOADING_PRERENDER_ENABLED = 1; // 0x1
+    field public static final int WEB_AUTHENTICATION_SUPPORT_FOR_APP = 1; // 0x1
+    field public static final int WEB_AUTHENTICATION_SUPPORT_FOR_BROWSER = 2; // 0x2
+    field public static final int WEB_AUTHENTICATION_SUPPORT_NONE = 0; // 0x0
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) public static @interface WebSettingsCompat.ExperimentalBackForwardCache {
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) public static @interface WebSettingsCompat.ExperimentalSpeculativeLoading {
+  }
+
+  public final class WebStorageCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void deleteBrowsingData(android.webkit.WebStorage, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void deleteBrowsingData(android.webkit.WebStorage, java.util.concurrent.Executor, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static String deleteBrowsingDataForSite(android.webkit.WebStorage, String, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static String deleteBrowsingDataForSite(android.webkit.WebStorage, String, java.util.concurrent.Executor, Runnable);
+  }
+
+  public final class WebViewAssetLoader {
+    method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
+    field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
+  }
+
+  public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public static final class WebViewAssetLoader.Builder {
+    ctor public WebViewAssetLoader.Builder();
+    method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
+    method public androidx.webkit.WebViewAssetLoader build();
+    method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
+    method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
+  }
+
+  public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
+    method @WorkerThread public android.webkit.WebResourceResponse handle(String);
+  }
+
+  public static interface WebViewAssetLoader.PathHandler {
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public class WebViewClientCompat extends android.webkit.WebViewClient {
+    ctor public WebViewClientCompat();
+    method @RequiresApi(android.os.Build.VERSION_CODES.M) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O_MR1) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
+    method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
+  }
+
+  public class WebViewCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.ScriptHandler addDocumentStartJavaScript(android.webkit.WebView, String, java.util.Set<java.lang.String!>);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+    method @AnyThread public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.Profile getProfile(android.webkit.WebView);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MUTE_AUDIO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static boolean isAudioMuted(android.webkit.WebView);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PRERENDER_WITH_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static void prerenderUrl(android.webkit.WebView, String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.PrerenderOperationCallback);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PRERENDER_WITH_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static void prerenderUrl(android.webkit.WebView, String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.SpeculativeLoadingParameters, androidx.webkit.PrerenderOperationCallback);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MUTE_AUDIO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setAudioMuted(android.webkit.WebView, boolean);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.DEFAULT_TRAFFICSTATS_TAGGING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDefaultTrafficStatsTag(int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setProfile(android.webkit.WebView, String);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @Deprecated @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+    method @Deprecated @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @SuppressCompatibility @AnyThread @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static void startUpWebView(androidx.webkit.WebViewStartUpConfig, androidx.webkit.WebViewCompat.WebViewStartUpCallback);
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface WebViewCompat.ExperimentalAsyncStartUp {
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface WebViewCompat.ExperimentalUrlPrerender {
+  }
+
+  public static interface WebViewCompat.VisualStateCallback {
+    method @UiThread public void onComplete(long);
+  }
+
+  public static interface WebViewCompat.WebMessageListener {
+    method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static interface WebViewCompat.WebViewStartUpCallback {
+    method public void onSuccess(androidx.webkit.WebViewStartUpResult);
+  }
+
+  public class WebViewFeature {
+    method public static boolean isFeatureSupported(String);
+    method public static boolean isStartupFeatureSupported(android.content.Context, String);
+    field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+    field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
+    field public static final String BACK_FORWARD_CACHE = "BACK_FORWARD_CACHE";
+    field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+    field public static final String DEFAULT_TRAFFICSTATS_TAGGING = "DEFAULT_TRAFFICSTATS_TAGGING";
+    field public static final String DELETE_BROWSING_DATA = "DELETE_BROWSING_DATA";
+    field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+    field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
+    field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
+    field public static final String FORCE_DARK = "FORCE_DARK";
+    field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
+    field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
+    field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
+    field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
+    field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
+    field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
+    field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+    field public static final String MULTI_PROFILE = "MULTI_PROFILE";
+    field public static final String MUTE_AUDIO = "MUTE_AUDIO";
+    field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+    field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+    field @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static final String PRERENDER_WITH_URL = "PRERENDER_URL_V2";
+    field @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final String PROFILE_URL_PREFETCH = "PREFETCH_URL_V3";
+    field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
+    field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
+    field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
+    field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
+    field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
+    field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
+    field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
+    field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
+    field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
+    field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
+    field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
+    field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
+    field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
+    field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
+    field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
+    field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
+    field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
+    field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
+    field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
+    field public static final String SPECULATIVE_LOADING = "SPECULATIVE_LOADING_STATUS";
+    field @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final String SPECULATIVE_LOADING_CONFIG = "SPECULATIVE_LOADING_CONFIG";
+    field public static final String STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES = "STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES";
+    field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
+    field public static final String STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS = "STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS";
+    field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
+    field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
+    field public static final String USER_AGENT_METADATA = "USER_AGENT_METADATA";
+    field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+    field public static final String WEBVIEW_MEDIA_INTEGRITY_API_STATUS = "WEBVIEW_MEDIA_INTEGRITY_API_STATUS";
+    field public static final String WEB_AUTHENTICATION = "WEB_AUTHENTICATION";
+    field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
+    field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
+    field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
+    field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
+    field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
+    field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
+    field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
+    field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
+    field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
+    field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
+    field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
+  }
+
+  @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public class WebViewMediaIntegrityApiStatusConfig {
+    ctor public WebViewMediaIntegrityApiStatusConfig(androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder);
+    method public int getDefaultStatus();
+    method public java.util.Map<java.lang.String!,java.lang.Integer!> getOverrideRules();
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_DISABLED = 0; // 0x0
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED = 2; // 0x2
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY = 1; // 0x1
+  }
+
+  public static final class WebViewMediaIntegrityApiStatusConfig.Builder {
+    ctor public WebViewMediaIntegrityApiStatusConfig.Builder(int);
+    method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder addOverrideRule(String, int);
+    method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig build();
+  }
+
+  public abstract class WebViewRenderProcess {
+    ctor public WebViewRenderProcess();
+    method public abstract boolean terminate();
+  }
+
+  public abstract class WebViewRenderProcessClient {
+    ctor public WebViewRenderProcessClient();
+    method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+    method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public final class WebViewStartUpConfig {
+    method public java.util.concurrent.Executor getBackgroundExecutor();
+    method public boolean shouldRunUiThreadStartUpTasks();
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static final class WebViewStartUpConfig.Builder {
+    ctor public WebViewStartUpConfig.Builder(java.util.concurrent.Executor);
+    method public androidx.webkit.WebViewStartUpConfig build();
+    method public androidx.webkit.WebViewStartUpConfig.Builder setShouldRunUiThreadStartUpTasks(boolean);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public interface WebViewStartUpResult {
+    method public java.util.List<androidx.webkit.BlockingStartUpLocation!>? getBlockingStartUpLocations();
+    method public Long? getMaxTimePerTaskInUiThreadMillis();
+    method public Long? getTotalTimeInUiThreadMillis();
+  }
+
+}
+
diff --git a/webkit/webkit/api/res-1.13.0-beta01.txt b/webkit/webkit/api/res-1.13.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webkit/webkit/api/res-1.13.0-beta01.txt
diff --git a/webkit/webkit/api/restricted_1.13.0-beta01.txt b/webkit/webkit/api/restricted_1.13.0-beta01.txt
new file mode 100644
index 0000000..4a0366f
--- /dev/null
+++ b/webkit/webkit/api/restricted_1.13.0-beta01.txt
@@ -0,0 +1,570 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public interface BlockingStartUpLocation {
+    method public String getStackInformation();
+  }
+
+  @AnyThread public class CookieManagerCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_COOKIE_INFO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.List<java.lang.String!> getCookieInfo(android.webkit.CookieManager, String);
+  }
+
+  public final class DropDataContentProvider extends android.content.ContentProvider {
+    ctor public DropDataContentProvider();
+    method public int delete(android.net.Uri, String?, String![]?);
+    method public String? getType(android.net.Uri);
+    method public android.net.Uri? insert(android.net.Uri, android.content.ContentValues?);
+    method public boolean onCreate();
+    method public android.database.Cursor? query(android.net.Uri, String![]?, String?, String![]?, String?);
+    method public int update(android.net.Uri, android.content.ContentValues?, String?, String![]?);
+  }
+
+  @UiThread public abstract class JavaScriptReplyProxy {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(byte[]);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class NoVarySearchHeader {
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader alwaysVaryData();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader neverVaryData();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader neverVaryExcept(boolean, java.util.List<java.lang.String!>);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static androidx.webkit.NoVarySearchHeader varyExcept(boolean, java.util.List<java.lang.String!>);
+    field public final java.util.List<java.lang.String!> consideredQueryParameters;
+    field public final boolean ignoreDifferencesInParameters;
+    field public final java.util.List<java.lang.String!> ignoredQueryParameters;
+    field public final boolean varyOnKeyOrder;
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public interface OutcomeReceiverCompat<T, E extends java.lang.Throwable> {
+    method public default void onError(E);
+    method public void onResult(T!);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class PrefetchException extends java.lang.Exception {
+    ctor public PrefetchException();
+    ctor public PrefetchException(String);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class PrefetchNetworkException extends androidx.webkit.PrefetchException {
+    ctor public PrefetchNetworkException();
+    ctor public PrefetchNetworkException(int);
+    ctor public PrefetchNetworkException(String);
+    ctor public PrefetchNetworkException(String, int);
+    field public static final int NO_HTTP_RESPONSE_STATUS_CODE = 0; // 0x0
+    field public final int httpResponseStatusCode;
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public class PrerenderException extends java.lang.Exception {
+    ctor public PrerenderException(String, Throwable?);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public interface PrerenderOperationCallback {
+    method public void onError(androidx.webkit.PrerenderException);
+    method public void onPrerenderActivated();
+  }
+
+  public class ProcessGlobalConfig {
+    ctor public ProcessGlobalConfig();
+    method public static void apply(androidx.webkit.ProcessGlobalConfig);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDataDirectorySuffix(android.content.Context, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setPartitionedCookiesEnabled(android.content.Context, boolean);
+  }
+
+  public interface Profile {
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void clearPrefetchAsync(String, java.util.concurrent.Executor, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void prefetchUrlAsync(String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void prefetchUrlAsync(String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.SpeculativeLoadingParameters, androidx.webkit.OutcomeReceiverCompat<java.lang.Void!,androidx.webkit.PrefetchException!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING_CONFIG, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.Profile.ExperimentalUrlPrefetch public void setSpeculativeLoadingConfig(androidx.webkit.SpeculativeLoadingConfig);
+    field public static final String DEFAULT_PROFILE_NAME = "Default";
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface Profile.ExperimentalUrlPrefetch {
+  }
+
+  @UiThread public interface ProfileStore {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+  }
+
+  public final class ProxyConfig {
+    method public java.util.List<java.lang.String!> getBypassRules();
+    method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
+    method public boolean isReverseBypassEnabled();
+    field public static final String MATCH_ALL_SCHEMES = "*";
+    field public static final String MATCH_HTTP = "http";
+    field public static final String MATCH_HTTPS = "https";
+  }
+
+  public static final class ProxyConfig.Builder {
+    ctor public ProxyConfig.Builder();
+    ctor public ProxyConfig.Builder(androidx.webkit.ProxyConfig);
+    method public androidx.webkit.ProxyConfig.Builder addBypassRule(String);
+    method public androidx.webkit.ProxyConfig.Builder addDirect();
+    method public androidx.webkit.ProxyConfig.Builder addDirect(String);
+    method public androidx.webkit.ProxyConfig.Builder addProxyRule(String);
+    method public androidx.webkit.ProxyConfig.Builder addProxyRule(String, String);
+    method public androidx.webkit.ProxyConfig build();
+    method public androidx.webkit.ProxyConfig.Builder bypassSimpleHostnames();
+    method public androidx.webkit.ProxyConfig.Builder removeImplicitRules();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE_REVERSE_BYPASS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.ProxyConfig.Builder setReverseBypassEnabled(boolean);
+  }
+
+  public static final class ProxyConfig.ProxyRule {
+    method public String getSchemeFilter();
+    method public String getUrl();
+  }
+
+  @AnyThread public abstract class ProxyController {
+    method public abstract void clearProxyOverride(java.util.concurrent.Executor, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.PROXY_OVERRIDE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProxyController getInstance();
+    method public abstract void setProxyOverride(androidx.webkit.ProxyConfig, java.util.concurrent.Executor, Runnable);
+  }
+
+  public abstract class SafeBrowsingResponseCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void backToSafety(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_PROCEED, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void proceed(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void showInterstitial(boolean);
+  }
+
+  public interface ScriptHandler {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public void remove();
+  }
+
+  public abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  @AnyThread public abstract class ServiceWorkerControllerCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+    method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat?);
+  }
+
+  @AnyThread public abstract class ServiceWorkerWebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowContentAccess();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getAllowFileAccess();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract boolean getBlockNetworkLoads();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getCacheMode();
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowContentAccess(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_FILE_ACCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setAllowFileAccess(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setBlockNetworkLoads(boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SERVICE_WORKER_CACHE_MODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setCacheMode(int);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setRequestedWithHeaderOriginAllowList(java.util.Set<java.lang.String!>);
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public class SpeculativeLoadingConfig {
+    method @IntRange(from=1, to=androidx.webkit.SpeculativeLoadingConfig.ABSOLUTE_MAX_PREFETCHES) public int getMaxPrefetches();
+    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getPrefetchTtlSeconds();
+    field public static final int ABSOLUTE_MAX_PREFETCHES = 20; // 0x14
+    field public static final int DEFAULT_MAX_PREFETCHES = 10; // 0xa
+    field public static final int DEFAULT_TTL_SECS = 60; // 0x3c
+  }
+
+  @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final class SpeculativeLoadingConfig.Builder {
+    ctor public SpeculativeLoadingConfig.Builder();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingConfig build();
+    method public androidx.webkit.SpeculativeLoadingConfig.Builder setMaxPrefetches(@IntRange(from=1, to=androidx.webkit.SpeculativeLoadingConfig.ABSOLUTE_MAX_PREFETCHES) int);
+    method public androidx.webkit.SpeculativeLoadingConfig.Builder setPrefetchTtlSeconds(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+  }
+
+  @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.Profile.ExperimentalUrlPrefetch public final class SpeculativeLoadingParameters {
+    method public java.util.Map<java.lang.String!,java.lang.String!> getAdditionalHeaders();
+    method public androidx.webkit.NoVarySearchHeader? getExpectedNoVarySearchData();
+    method public boolean isJavaScriptEnabled();
+  }
+
+  public static final class SpeculativeLoadingParameters.Builder {
+    ctor public SpeculativeLoadingParameters.Builder();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder addAdditionalHeader(String, String);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder addAdditionalHeaders(java.util.Map<java.lang.String!,java.lang.String!>);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PROFILE_URL_PREFETCH, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters build();
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder setExpectedNoVarySearchData(androidx.webkit.NoVarySearchHeader);
+    method @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public androidx.webkit.SpeculativeLoadingParameters.Builder setJavaScriptEnabled(boolean);
+  }
+
+  public class TracingConfig {
+    method public java.util.List<java.lang.String!> getCustomIncludedCategories();
+    method public int getPredefinedCategories();
+    method public int getTracingMode();
+    field public static final int CATEGORIES_ALL = 1; // 0x1
+    field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+    field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+    field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+    field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+    field public static final int CATEGORIES_NONE = 0; // 0x0
+    field public static final int CATEGORIES_RENDERING = 16; // 0x10
+    field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
+    field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
+    field public static final int RECORD_UNTIL_FULL = 0; // 0x0
+  }
+
+  public static class TracingConfig.Builder {
+    ctor public TracingConfig.Builder();
+    method public androidx.webkit.TracingConfig.Builder addCategories(int...);
+    method public androidx.webkit.TracingConfig.Builder addCategories(java.lang.String!...);
+    method public androidx.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String!>);
+    method public androidx.webkit.TracingConfig build();
+    method public androidx.webkit.TracingConfig.Builder setTracingMode(int);
+  }
+
+  @AnyThread public abstract class TracingController {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.TracingController getInstance();
+    method public abstract boolean isTracing();
+    method public abstract void start(androidx.webkit.TracingConfig);
+    method public abstract boolean stop(java.io.OutputStream?, java.util.concurrent.Executor);
+  }
+
+  public final class URLUtilCompat {
+    method public static String? getFilenameFromContentDisposition(String);
+    method public static String guessFileName(String, String?, String?);
+  }
+
+  public final class UserAgentMetadata {
+    method public String? getArchitecture();
+    method public int getBitness();
+    method public java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!> getBrandVersionList();
+    method public String? getFullVersion();
+    method public String? getModel();
+    method public String? getPlatform();
+    method public String? getPlatformVersion();
+    method public boolean isMobile();
+    method public boolean isWow64();
+    field public static final int BITNESS_DEFAULT = 0; // 0x0
+  }
+
+  public static final class UserAgentMetadata.BrandVersion {
+    method public String getBrand();
+    method public String getFullVersion();
+    method public String getMajorVersion();
+  }
+
+  public static final class UserAgentMetadata.BrandVersion.Builder {
+    ctor public UserAgentMetadata.BrandVersion.Builder();
+    ctor public UserAgentMetadata.BrandVersion.Builder(androidx.webkit.UserAgentMetadata.BrandVersion);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion build();
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setBrand(String);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setFullVersion(String);
+    method public androidx.webkit.UserAgentMetadata.BrandVersion.Builder setMajorVersion(String);
+  }
+
+  public static final class UserAgentMetadata.Builder {
+    ctor public UserAgentMetadata.Builder();
+    ctor public UserAgentMetadata.Builder(androidx.webkit.UserAgentMetadata);
+    method public androidx.webkit.UserAgentMetadata build();
+    method public androidx.webkit.UserAgentMetadata.Builder setArchitecture(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setBitness(int);
+    method public androidx.webkit.UserAgentMetadata.Builder setBrandVersionList(java.util.List<androidx.webkit.UserAgentMetadata.BrandVersion!>);
+    method public androidx.webkit.UserAgentMetadata.Builder setFullVersion(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setMobile(boolean);
+    method public androidx.webkit.UserAgentMetadata.Builder setModel(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setPlatform(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setPlatformVersion(String?);
+    method public androidx.webkit.UserAgentMetadata.Builder setWow64(boolean);
+  }
+
+  public class WebMessageCompat {
+    ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[]);
+    ctor @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public WebMessageCompat(byte[], androidx.webkit.WebMessagePortCompat![]?);
+    ctor public WebMessageCompat(String?);
+    ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+    method public byte[] getArrayBuffer();
+    method public String? getData();
+    method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+    method public int getType();
+    field public static final int TYPE_ARRAY_BUFFER = 1; // 0x1
+    field public static final int TYPE_STRING = 0; // 0x0
+  }
+
+  @AnyThread public abstract class WebMessagePortCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_CLOSE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void close();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_POST_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(androidx.webkit.WebMessageCompat);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(android.os.Handler?, androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void setWebMessageCallback(androidx.webkit.WebMessagePortCompat.WebMessageCallbackCompat);
+  }
+
+  public abstract static class WebMessagePortCompat.WebMessageCallbackCompat {
+    ctor public WebMessagePortCompat.WebMessageCallbackCompat();
+    method public void onMessage(androidx.webkit.WebMessagePortCompat, androidx.webkit.WebMessageCompat?);
+  }
+
+  public abstract class WebResourceErrorCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract CharSequence getDescription();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_ERROR_GET_CODE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract int getErrorCode();
+  }
+
+  public class WebResourceRequestCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isRedirect(android.webkit.WebResourceRequest);
+  }
+
+  public class WebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.BACK_FORWARD_CACHE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalBackForwardCache public static boolean getBackForwardCacheEnabled(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDarkStrategy(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static java.util.Set<java.lang.String!> getRequestedWithHeaderOriginAllowList(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static int getSpeculativeLoadingStatus(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_AUTHENTICATION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static int getWebAuthenticationSupport(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebViewMediaIntegrityApiStatusConfig getWebViewMediaIntegrityApiStatus(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.BACK_FORWARD_CACHE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalBackForwardCache public static void setBackForwardCacheEnabled(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
+    method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK_STRATEGY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDarkStrategy(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.OFF_SCREEN_PRERASTER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.SPECULATIVE_LOADING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static void setSpeculativeLoadingStatus(android.webkit.WebSettings, @SuppressCompatibility int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_AUTHENTICATION, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebAuthenticationSupport(android.webkit.WebSettings, int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewMediaIntegrityApiStatus(android.webkit.WebSettings, androidx.webkit.WebViewMediaIntegrityApiStatusConfig);
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+    field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+    field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
+    field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
+    field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
+    field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
+    field @Deprecated public static final int FORCE_DARK_AUTO = 1; // 0x1
+    field @Deprecated public static final int FORCE_DARK_OFF = 0; // 0x0
+    field @Deprecated public static final int FORCE_DARK_ON = 2; // 0x2
+    field @SuppressCompatibility @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static final int SPECULATIVE_LOADING_DISABLED = 0; // 0x0
+    field @SuppressCompatibility @androidx.webkit.WebSettingsCompat.ExperimentalSpeculativeLoading public static final int SPECULATIVE_LOADING_PRERENDER_ENABLED = 1; // 0x1
+    field public static final int WEB_AUTHENTICATION_SUPPORT_FOR_APP = 1; // 0x1
+    field public static final int WEB_AUTHENTICATION_SUPPORT_FOR_BROWSER = 2; // 0x2
+    field public static final int WEB_AUTHENTICATION_SUPPORT_NONE = 0; // 0x0
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) public static @interface WebSettingsCompat.ExperimentalBackForwardCache {
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) public static @interface WebSettingsCompat.ExperimentalSpeculativeLoading {
+  }
+
+  public final class WebStorageCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void deleteBrowsingData(android.webkit.WebStorage, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void deleteBrowsingData(android.webkit.WebStorage, java.util.concurrent.Executor, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static String deleteBrowsingDataForSite(android.webkit.WebStorage, String, Runnable);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DELETE_BROWSING_DATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static String deleteBrowsingDataForSite(android.webkit.WebStorage, String, java.util.concurrent.Executor, Runnable);
+  }
+
+  public final class WebViewAssetLoader {
+    method @WorkerThread public android.webkit.WebResourceResponse? shouldInterceptRequest(android.net.Uri);
+    field public static final String DEFAULT_DOMAIN = "appassets.androidplatform.net";
+  }
+
+  public static final class WebViewAssetLoader.AssetsPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.AssetsPathHandler(android.content.Context);
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public static final class WebViewAssetLoader.Builder {
+    ctor public WebViewAssetLoader.Builder();
+    method public androidx.webkit.WebViewAssetLoader.Builder addPathHandler(String, androidx.webkit.WebViewAssetLoader.PathHandler);
+    method public androidx.webkit.WebViewAssetLoader build();
+    method public androidx.webkit.WebViewAssetLoader.Builder setDomain(String);
+    method public androidx.webkit.WebViewAssetLoader.Builder setHttpAllowed(boolean);
+  }
+
+  public static final class WebViewAssetLoader.InternalStoragePathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.InternalStoragePathHandler(android.content.Context, java.io.File);
+    method @WorkerThread public android.webkit.WebResourceResponse handle(String);
+  }
+
+  public static interface WebViewAssetLoader.PathHandler {
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public static final class WebViewAssetLoader.ResourcesPathHandler implements androidx.webkit.WebViewAssetLoader.PathHandler {
+    ctor public WebViewAssetLoader.ResourcesPathHandler(android.content.Context);
+    method @WorkerThread public android.webkit.WebResourceResponse? handle(String);
+  }
+
+  public class WebViewClientCompat extends android.webkit.WebViewClient {
+    ctor public WebViewClientCompat();
+    method @RequiresApi(android.os.Build.VERSION_CODES.M) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+    method @RequiresApi(android.os.Build.VERSION_CODES.O_MR1) public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
+    method @UiThread public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
+  }
+
+  public class WebViewCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.DOCUMENT_START_SCRIPT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.ScriptHandler addDocumentStartJavaScript(android.webkit.WebView, String, java.util.Set<java.lang.String!>);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+    method @AnyThread public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.Profile getProfile(android.webkit.WebView);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebViewRenderProcess? getWebViewRenderProcess(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MUTE_AUDIO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static boolean isAudioMuted(android.webkit.WebView);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROCESS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isMultiProcessEnabled();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PRERENDER_WITH_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static void prerenderUrl(android.webkit.WebView, String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.PrerenderOperationCallback);
+    method @SuppressCompatibility @RequiresFeature(name=androidx.webkit.WebViewFeature.PRERENDER_WITH_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static void prerenderUrl(android.webkit.WebView, String, android.os.CancellationSignal?, java.util.concurrent.Executor, androidx.webkit.SpeculativeLoadingParameters, androidx.webkit.PrerenderOperationCallback);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MUTE_AUDIO, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setAudioMuted(android.webkit.WebView, boolean);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.DEFAULT_TRAFFICSTATS_TAGGING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDefaultTrafficStatsTag(int);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setProfile(android.webkit.WebView, String);
+    method @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @Deprecated @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") @UiThread public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+    method @Deprecated @AnyThread @RequiresFeature(name=androidx.webkit.WebViewFeature.START_SAFE_BROWSING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean!>?);
+    method @SuppressCompatibility @AnyThread @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static void startUpWebView(androidx.webkit.WebViewStartUpConfig, androidx.webkit.WebViewCompat.WebViewStartUpCallback);
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface WebViewCompat.ExperimentalAsyncStartUp {
+  }
+
+  @SuppressCompatibility @RequiresOptIn(level=androidx.annotation.RequiresOptIn.Level.ERROR) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD}) public static @interface WebViewCompat.ExperimentalUrlPrerender {
+  }
+
+  public static interface WebViewCompat.VisualStateCallback {
+    method @UiThread public void onComplete(long);
+  }
+
+  public static interface WebViewCompat.WebMessageListener {
+    method @UiThread public void onPostMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri, boolean, androidx.webkit.JavaScriptReplyProxy);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static interface WebViewCompat.WebViewStartUpCallback {
+    method public void onSuccess(androidx.webkit.WebViewStartUpResult);
+  }
+
+  public class WebViewFeature {
+    method public static boolean isFeatureSupported(String);
+    method public static boolean isStartupFeatureSupported(android.content.Context, String);
+    field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+    field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
+    field public static final String BACK_FORWARD_CACHE = "BACK_FORWARD_CACHE";
+    field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+    field public static final String DEFAULT_TRAFFICSTATS_TAGGING = "DEFAULT_TRAFFICSTATS_TAGGING";
+    field public static final String DELETE_BROWSING_DATA = "DELETE_BROWSING_DATA";
+    field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+    field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
+    field public static final String ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY = "ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY";
+    field public static final String FORCE_DARK = "FORCE_DARK";
+    field public static final String FORCE_DARK_STRATEGY = "FORCE_DARK_STRATEGY";
+    field public static final String GET_COOKIE_INFO = "GET_COOKIE_INFO";
+    field public static final String GET_VARIATIONS_HEADER = "GET_VARIATIONS_HEADER";
+    field public static final String GET_WEB_CHROME_CLIENT = "GET_WEB_CHROME_CLIENT";
+    field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
+    field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
+    field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+    field public static final String MULTI_PROFILE = "MULTI_PROFILE";
+    field public static final String MUTE_AUDIO = "MUTE_AUDIO";
+    field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+    field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+    field @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalUrlPrerender public static final String PRERENDER_WITH_URL = "PRERENDER_URL_V2";
+    field @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final String PROFILE_URL_PREFETCH = "PREFETCH_URL_V3";
+    field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
+    field public static final String PROXY_OVERRIDE_REVERSE_BYPASS = "PROXY_OVERRIDE_REVERSE_BYPASS";
+    field public static final String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
+    field public static final String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
+    field public static final String SAFE_BROWSING_ALLOWLIST = "SAFE_BROWSING_ALLOWLIST";
+    field public static final String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
+    field public static final String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
+    field public static final String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
+    field public static final String SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY = "SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY";
+    field public static final String SAFE_BROWSING_RESPONSE_PROCEED = "SAFE_BROWSING_RESPONSE_PROCEED";
+    field public static final String SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL = "SAFE_BROWSING_RESPONSE_SHOW_INTERSTITIAL";
+    field @Deprecated public static final String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
+    field public static final String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
+    field public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
+    field public static final String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
+    field public static final String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
+    field public static final String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
+    field public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
+    field public static final String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
+    field public static final String SPECULATIVE_LOADING = "SPECULATIVE_LOADING_STATUS";
+    field @SuppressCompatibility @androidx.webkit.Profile.ExperimentalUrlPrefetch public static final String SPECULATIVE_LOADING_CONFIG = "SPECULATIVE_LOADING_CONFIG";
+    field public static final String STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES = "STARTUP_FEATURE_CONFIGURE_PARTITIONED_COOKIES";
+    field public static final String STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX = "STARTUP_FEATURE_SET_DATA_DIRECTORY_SUFFIX";
+    field public static final String STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS = "STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS";
+    field public static final String START_SAFE_BROWSING = "START_SAFE_BROWSING";
+    field public static final String TRACING_CONTROLLER_BASIC_USAGE = "TRACING_CONTROLLER_BASIC_USAGE";
+    field public static final String USER_AGENT_METADATA = "USER_AGENT_METADATA";
+    field public static final String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+    field public static final String WEBVIEW_MEDIA_INTEGRITY_API_STATUS = "WEBVIEW_MEDIA_INTEGRITY_API_STATUS";
+    field public static final String WEB_AUTHENTICATION = "WEB_AUTHENTICATION";
+    field public static final String WEB_MESSAGE_ARRAY_BUFFER = "WEB_MESSAGE_ARRAY_BUFFER";
+    field public static final String WEB_MESSAGE_CALLBACK_ON_MESSAGE = "WEB_MESSAGE_CALLBACK_ON_MESSAGE";
+    field public static final String WEB_MESSAGE_LISTENER = "WEB_MESSAGE_LISTENER";
+    field public static final String WEB_MESSAGE_PORT_CLOSE = "WEB_MESSAGE_PORT_CLOSE";
+    field public static final String WEB_MESSAGE_PORT_POST_MESSAGE = "WEB_MESSAGE_PORT_POST_MESSAGE";
+    field public static final String WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK = "WEB_MESSAGE_PORT_SET_MESSAGE_CALLBACK";
+    field public static final String WEB_RESOURCE_ERROR_GET_CODE = "WEB_RESOURCE_ERROR_GET_CODE";
+    field public static final String WEB_RESOURCE_ERROR_GET_DESCRIPTION = "WEB_RESOURCE_ERROR_GET_DESCRIPTION";
+    field public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
+    field public static final String WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE = "WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE";
+    field public static final String WEB_VIEW_RENDERER_TERMINATE = "WEB_VIEW_RENDERER_TERMINATE";
+  }
+
+  @RequiresFeature(name=androidx.webkit.WebViewFeature.WEBVIEW_MEDIA_INTEGRITY_API_STATUS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public class WebViewMediaIntegrityApiStatusConfig {
+    ctor public WebViewMediaIntegrityApiStatusConfig(androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder);
+    method public int getDefaultStatus();
+    method public java.util.Map<java.lang.String!,java.lang.Integer!> getOverrideRules();
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_DISABLED = 0; // 0x0
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED = 2; // 0x2
+    field public static final int WEBVIEW_MEDIA_INTEGRITY_API_ENABLED_WITHOUT_APP_IDENTITY = 1; // 0x1
+  }
+
+  public static final class WebViewMediaIntegrityApiStatusConfig.Builder {
+    ctor public WebViewMediaIntegrityApiStatusConfig.Builder(int);
+    method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig.Builder addOverrideRule(String, int);
+    method public androidx.webkit.WebViewMediaIntegrityApiStatusConfig build();
+  }
+
+  public abstract class WebViewRenderProcess {
+    ctor public WebViewRenderProcess();
+    method public abstract boolean terminate();
+  }
+
+  public abstract class WebViewRenderProcessClient {
+    ctor public WebViewRenderProcessClient();
+    method public abstract void onRenderProcessResponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+    method public abstract void onRenderProcessUnresponsive(android.webkit.WebView, androidx.webkit.WebViewRenderProcess?);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public final class WebViewStartUpConfig {
+    method public java.util.concurrent.Executor getBackgroundExecutor();
+    method public boolean shouldRunUiThreadStartUpTasks();
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public static final class WebViewStartUpConfig.Builder {
+    ctor public WebViewStartUpConfig.Builder(java.util.concurrent.Executor);
+    method public androidx.webkit.WebViewStartUpConfig build();
+    method public androidx.webkit.WebViewStartUpConfig.Builder setShouldRunUiThreadStartUpTasks(boolean);
+  }
+
+  @SuppressCompatibility @androidx.webkit.WebViewCompat.ExperimentalAsyncStartUp public interface WebViewStartUpResult {
+    method public java.util.List<androidx.webkit.BlockingStartUpLocation!>? getBlockingStartUpLocations();
+    method public Long? getMaxTimePerTaskInUiThreadMillis();
+    method public Long? getTotalTimeInUiThreadMillis();
+  }
+
+}
+
diff --git a/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java b/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
index 4761400..487fc51 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/URLUtilCompat.java
@@ -34,7 +34,6 @@
  *
  * @see android.webkit.URLUtil
  */
-@SuppressWarnings("AcronymName") // Compat class for similarly named URLUtil in Android SDK
 public final class URLUtilCompat {
 
     private URLUtilCompat() {} // Class should not be instantiated
diff --git a/work/work-runtime/src/main/java/androidx/work/ListenableWorker.java b/work/work-runtime/src/main/java/androidx/work/ListenableWorker.java
index 3d5d37b..2fd3013 100644
--- a/work/work-runtime/src/main/java/androidx/work/ListenableWorker.java
+++ b/work/work-runtime/src/main/java/androidx/work/ListenableWorker.java
@@ -394,8 +394,8 @@
          * Returns an instance of {@link Result} that can be used to indicate that the work
          * completed with a permanent failure. Any work that depends on this will also be marked as
          * failed and will not be run. <b>If you need child workers to run, you need to use
-         * {@link #success()} or {@link #success(Data)}</b>; failure indicates a permanent stoppage
-         * of the chain of work.
+         * {@link #success()} or {@link #success(Data) success(Data)}</b>; failure indicates a
+         * permanent stoppage of the chain of work.
          *
          * @return An instance of {@link Result} indicating failure when executing work
          */
@@ -407,8 +407,8 @@
          * Returns an instance of {@link Result} that can be used to indicate that the work
          * completed with a permanent failure. Any work that depends on this will also be marked as
          * failed and will not be run. <b>If you need child workers to run, you need to use
-         * {@link #success()} or {@link #success(Data)}</b>; failure indicates a permanent stoppage
-         * of the chain of work.
+         * {@link #success()} or {@link #success(Data) success(Data)}</b>; failure indicates a
+         * permanent stoppage of the chain of work.
          *
          * @param outputData A {@link Data} object that can be used to keep track of why the work
          *                   failed
diff --git a/xr/arcore/integration-tests/whitebox/build.gradle b/xr/arcore/integration-tests/whitebox/build.gradle
new file mode 100644
index 0000000..69337e6
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/build.gradle
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file was created using the `create_project.py` script located in the
+ * `<AndroidX root>/development/project-creator` directory.
+ *
+ * Please use that script when creating a new project, rather than copying an existing project and
+ * modifying its settings.
+ */
+
+import androidx.build.ApkCopyHelperKt
+import androidx.build.KotlinTarget
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("AndroidXComposePlugin")
+    id("com.android.application")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    defaultConfig {
+        // TODO: This should be lower, possibly 21.
+        //       Address API calls that require higher versions.
+        minSdkVersion 30
+    }
+    buildFeatures { viewBinding = true }
+    namespace = "androidx.xr.arcore.apps.whitebox"
+}
+
+androidx {
+    name = "ARCore Whitebox"
+    type = LibraryType.TEST_APPLICATION
+    inceptionYear = "2024"
+    description = "Test app that exercises the ARCore APIs."
+    kotlinTarget = KotlinTarget.KOTLIN_1_9
+    // TODO: b/326456246
+    optOutJSpecify = true
+}
+
+dependencies {
+    implementation(project(":xr:arcore:arcore"))
+    implementation(project(":xr:assets"))
+    implementation(project(":xr:compose:compose"))
+    implementation(project(":xr:scenecore:scenecore"))
+
+    implementation(libs.kotlinStdlib)
+    implementation(libs.kotlinCoroutinesGuava)
+    implementation("androidx.activity:activity-compose:1.9.3")
+    implementation("androidx.appcompat:appcompat:1.7.0")
+    implementation("androidx.compose.foundation:foundation-layout:1.7.5")
+    implementation("androidx.compose.material3:material3:1.3.1")
+    implementation("androidx.compose.runtime:runtime:1.7.5")
+    implementation("androidx.compose.ui:ui:1.7.5")
+    implementation("androidx.lifecycle:lifecycle-runtime:2.8.7")
+}
+
+// Making this APK available via Android Build so the QA team can
+// access it in a convenient manner.
+ApkCopyHelperKt.setupAppApkCopy(project, "release")
diff --git a/xr/arcore/integration-tests/whitebox/src/main/AndroidManifest.xml b/xr/arcore/integration-tests/whitebox/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..706b854
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+  <uses-permission android:name="android.permission.SCENE_UNDERSTANDING" />
+  <application android:label="ARCore Whitebox" android:taskAffinity="">
+    <activity
+        android:name=".MainActivity"
+        android:exported="true"
+        android:theme="@style/Theme.AppCompat.NoActionBar">
+      <property
+          android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
+          android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" />
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN"/>
+        <category android:name="android.intent.category.LAUNCHER"/>
+      </intent-filter>
+    </activity>
+    <activity
+        android:name=".helloar.HelloArActivity"
+        android:exported="true"
+        android:theme="@style/Theme.AppCompat.NoActionBar">
+    </activity>
+     <activity
+        android:name=".persistentanchors.PersistentAnchorsActivity"
+        android:exported="true"
+        android:theme="@style/Theme.AppCompat.NoActionBar">
+    </activity>
+  </application>
+</manifest>
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/MainActivity.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/MainActivity.kt
new file mode 100644
index 0000000..5a4dc72
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/MainActivity.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.xr.arcore.apps.whitebox
+
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Card
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.xr.arcore.apps.whitebox.helloar.HelloArActivity as HelloArActivity
+import androidx.xr.arcore.apps.whitebox.persistentanchors.PersistentAnchorsActivity as PersistentAnchorsActivity
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+/** Entrypoint for testing various ARCore for Android XR functionalities. */
+class MainActivity : ComponentActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        setContent { WhiteboxHomeScreen() }
+    }
+}
+
+@Composable
+fun WhiteboxHomeScreen(modifier: Modifier = Modifier) {
+    Surface(modifier = modifier.fillMaxSize(), color = Color.White) {
+        Column() {
+            Text(
+                "AR Whitebox Test Application",
+                modifier = Modifier.padding(20.dp),
+                fontSize = 30.sp,
+                color = Color.Black,
+            )
+            VersionInfoCard()
+            WhiteboxSessionMenu()
+        }
+    }
+}
+
+@Composable
+fun VersionInfoCard() {
+    Card {
+        Column(modifier = Modifier.padding(16.dp)) {
+            Text("Build Fingerprint: ${Build.FINGERPRINT}")
+            Text(
+                "Date: ${SimpleDateFormat("dd MMMM yyyy, HH:mm:ss", Locale.ENGLISH).format(Build.TIME)}"
+            )
+            Text("CL Number: N/A")
+        }
+    }
+}
+
+@Composable
+fun WhiteboxSessionMenu() {
+    val context = LocalContext.current
+
+    Column(modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally) {
+        Text(
+            "Test Activity List",
+            modifier = Modifier.padding(20.dp),
+            fontSize = 20.sp,
+            fontWeight = FontWeight.Bold,
+            color = Color.Black,
+        )
+        HorizontalDivider()
+        TextButton(
+            onClick = { context.startActivity(Intent(context, HelloArActivity::class.java)) }
+        ) {
+            Text("Hello AR")
+        }
+        TextButton(
+            onClick = {
+                context.startActivity(Intent(context, PersistentAnchorsActivity::class.java))
+            }
+        ) {
+            Text("Persistent Anchors")
+        }
+    }
+}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/Composables.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/Composables.kt
new file mode 100644
index 0000000..4377346
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/Composables.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.xr.arcore.apps.whitebox.common
+
+import android.app.Activity
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.FilledTonalButton
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.xr.arcore.Plane
+import androidx.xr.arcore.Trackable
+
+@Composable
+fun BackToMainActivityButton() {
+    val context = LocalContext.current
+    FilledTonalButton(onClick = { (context as Activity).finish() }) { Text("Go Back") }
+}
+
+@Composable
+fun TrackablesList(trackables: List<Trackable<Trackable.State>>) {
+    LazyColumn { items(trackables) { trackable -> TrackableCard(trackable) } }
+}
+
+@Composable
+fun TrackableCard(trackable: Trackable<Trackable.State>) {
+    val state = trackable.state.collectAsStateWithLifecycle()
+    OutlinedCard(
+        colors = CardDefaults.cardColors(),
+        modifier = Modifier.padding(8.dp).fillMaxWidth(),
+    ) {
+        Column(modifier = Modifier.padding(16.dp)) {
+            Text(text = "Trackable ID: ${trackable}")
+            Text(text = "Tracking State: ${state.value.trackingState}")
+            if (trackable is Plane) {
+                Text("Plane Type: ${trackable.type}")
+                PlaneStateInfo(state.value as Plane.State)
+            }
+        }
+    }
+}
+
+@Composable
+fun PlaneStateInfo(state: Plane.State) {
+    Text(
+        text = "Plane Label: ${state.label}",
+        color = convertPlaneLabelToColor(state.label),
+    )
+    Text(text = "Plane Center Pose: ${state.centerPose}")
+    Text(text = "Plane Extents: ${state.extents}")
+    Text(text = "Subsumed by Plane: ${state.subsumedBy}")
+    Text(text = "Plane Vertices: ${state.vertices}")
+}
+
+private fun convertPlaneLabelToColor(label: Plane.Label): Color =
+    when (label) {
+        Plane.Label.Wall -> Color.Green
+        Plane.Label.Floor -> Color.Blue
+        Plane.Label.Ceiling -> Color.Yellow
+        Plane.Label.Table -> Color.Magenta
+        else -> Color.Red
+    }
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/SessionLifecycleHelper.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/SessionLifecycleHelper.kt
new file mode 100644
index 0000000..87d8402
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/common/SessionLifecycleHelper.kt
@@ -0,0 +1,123 @@
+/*
+ * 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.xr.arcore.apps.whitebox.common
+
+import android.util.Log
+import android.widget.Toast
+import androidx.activity.ComponentActivity
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
+import androidx.activity.result.registerForActivityResult
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.xr.runtime.Session
+import androidx.xr.runtime.SessionCreatePermissionsNotGranted
+import androidx.xr.runtime.SessionCreateSuccess
+import androidx.xr.runtime.SessionResumePermissionsNotGranted
+import androidx.xr.runtime.SessionResumeSuccess
+
+/**
+ * Observer class to manage the lifecycle of the Jetpack XR Runtime Session based on the lifecycle
+ * owner (activity).
+ */
+class SessionLifecycleHelper(
+    internal val onCreateCallback: (Session) -> Unit,
+    internal val onResumeCallback: (() -> Unit)? = null,
+    internal val beforePauseCallback: (() -> Unit)? = null,
+) : DefaultLifecycleObserver {
+
+    internal lateinit var session: Session
+    internal lateinit var requestPermissionLauncher: ActivityResultLauncher<Array<String>>
+
+    override fun onCreate(owner: LifecycleOwner) {
+        // Sessions can only be instantiated with an instance of [ComponentActivity].
+        check(owner is ComponentActivity) { "owner is not an instance of ComponentActivity" }
+
+        registerRequestPermissionLauncher(owner)
+
+        when (val result = Session.create(owner)) {
+            is SessionCreateSuccess -> {
+                session = result.session
+                onCreateCallback.invoke(session)
+            }
+            is SessionCreatePermissionsNotGranted -> {
+                requestPermissionLauncher.launch(result.permissions.toTypedArray())
+            }
+        }
+    }
+
+    override fun onResume(owner: LifecycleOwner) {
+        if (!this::session.isInitialized) {
+            return
+        }
+        when (val result = session.resume()) {
+            is SessionResumeSuccess -> {
+                onResumeCallback?.invoke()
+            }
+            is SessionResumePermissionsNotGranted -> {
+                requestPermissionLauncher.launch(result.permissions.toTypedArray())
+            }
+            else -> {
+                showErrorMessage("Attempted to resume while session is null.")
+            }
+        }
+    }
+
+    override fun onPause(owner: LifecycleOwner) {
+        if (!this::session.isInitialized) {
+            return
+        }
+        beforePauseCallback?.invoke()
+        session.pause()
+    }
+
+    override fun onDestroy(owner: LifecycleOwner) {
+        if (!this::session.isInitialized) {
+            return
+        }
+        session.destroy()
+    }
+
+    private fun registerRequestPermissionLauncher(activity: ComponentActivity) {
+        requestPermissionLauncher =
+            activity.registerForActivityResult(
+                ActivityResultContracts.RequestMultiplePermissions()
+            ) { permissions ->
+                val allPermissionsGranted = permissions.all { it.value }
+                if (!allPermissionsGranted) {
+                    Toast.makeText(
+                            activity,
+                            "Required permissions were not granted, closing activity. ",
+                            Toast.LENGTH_LONG,
+                        )
+                        .show()
+                    activity.finish()
+                } else {
+                    activity.recreate()
+                }
+            }
+    }
+
+    private fun <F> showErrorMessage(error: F) {
+        Log.e(TAG, error.toString())
+    }
+
+    companion object {
+        private val TAG = this::class.simpleName
+    }
+}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/HelloArActivity.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/HelloArActivity.kt
new file mode 100644
index 0000000..d8683a5
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/HelloArActivity.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.xr.arcore.apps.whitebox.helloar
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.xr.arcore.apps.whitebox.common.BackToMainActivityButton
+import androidx.xr.arcore.apps.whitebox.common.SessionLifecycleHelper
+import androidx.xr.arcore.apps.whitebox.common.TrackablesList
+import androidx.xr.arcore.apps.whitebox.helloar.rendering.AnchorRenderer
+import androidx.xr.arcore.apps.whitebox.helloar.rendering.PlaneRenderer
+import androidx.xr.arcore.perceptionState
+import androidx.xr.runtime.Session
+import androidx.xr.scenecore.Session as JxrCoreSession
+
+/** Sample that demonstrates fundamental ARCore for Android XR usage. */
+class HelloArActivity : ComponentActivity() {
+
+    private lateinit var session: Session
+    private lateinit var sessionHelper: SessionLifecycleHelper
+
+    private lateinit var jxrCoreSession: JxrCoreSession
+
+    private var planeRenderer: PlaneRenderer? = null
+    private var anchorRenderer: AnchorRenderer? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        // Create session and renderers.
+        sessionHelper =
+            SessionLifecycleHelper(
+                onCreateCallback = {
+                    session = it
+                    jxrCoreSession = JxrCoreSession.create(this)
+                    planeRenderer = PlaneRenderer(session, jxrCoreSession, lifecycleScope)
+                    anchorRenderer =
+                        AnchorRenderer(
+                            this,
+                            planeRenderer!!,
+                            session,
+                            jxrCoreSession,
+                            lifecycleScope
+                        )
+                    setContent { HelloWorld(session) }
+                },
+                onResumeCallback = {
+                    planeRenderer?.startRendering()
+                    anchorRenderer?.startRendering()
+                },
+                beforePauseCallback = {
+                    planeRenderer?.stopRendering()
+                    anchorRenderer?.stopRendering()
+                },
+            )
+        lifecycle.addObserver(sessionHelper)
+    }
+}
+
+@Composable
+fun HelloWorld(session: Session) {
+    val state by session.state.collectAsStateWithLifecycle()
+    val perceptionState = state.perceptionState
+
+    Column(modifier = Modifier.background(color = Color.White)) {
+        BackToMainActivityButton()
+        Text(text = "CoreState: ${state.timeMark}")
+        if (perceptionState != null) {
+            TrackablesList(perceptionState.trackables.toList())
+        } else {
+            Text("PerceptionState is null.")
+        }
+    }
+}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorModel.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorModel.kt
new file mode 100644
index 0000000..a721aff
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorModel.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.xr.arcore.apps.whitebox.helloar.rendering
+
+import androidx.xr.arcore.Anchor
+import androidx.xr.scenecore.Entity
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.StateFlow
+
+/** Represents a rendered anchor model. */
+data class AnchorModel(
+    val id: Int,
+    val stateFlow: StateFlow<Anchor.State>,
+    internal val entity: Entity,
+    internal val renderJob: Job?,
+) {}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorRenderer.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorRenderer.kt
new file mode 100644
index 0000000..a56dacb
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/AnchorRenderer.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.xr.arcore.apps.whitebox.helloar.rendering
+
+import android.app.Activity
+import android.util.Log
+import androidx.xr.arcore.Anchor
+import androidx.xr.arcore.AnchorCreateResourcesExhausted
+import androidx.xr.arcore.AnchorCreateSuccess
+import androidx.xr.arcore.Plane
+import androidx.xr.arcore.TrackingState
+import androidx.xr.arcore.hitTest
+import androidx.xr.runtime.Session
+import androidx.xr.runtime.math.Pose
+import androidx.xr.runtime.math.Quaternion
+import androidx.xr.runtime.math.Ray
+import androidx.xr.runtime.math.Vector3
+import androidx.xr.scenecore.GltfModel
+import androidx.xr.scenecore.InputEvent
+import androidx.xr.scenecore.InteractableComponent
+import androidx.xr.scenecore.Session as JxrCoreSession
+import kotlinx.coroutines.CompletableJob
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.launch
+
+/** Class that keeps track of anchors rendered as GLTF models in a SceneCore session. */
+internal class AnchorRenderer(
+    val activity: Activity,
+    val planeRenderer: PlaneRenderer,
+    val session: Session,
+    val renderSession: JxrCoreSession,
+    val coroutineScope: CoroutineScope,
+) {
+
+    private lateinit var gltfAnchorModel: GltfModel
+
+    private val renderedAnchors: MutableList<AnchorModel> = mutableListOf<AnchorModel>()
+
+    private lateinit var updateJob: CompletableJob
+
+    internal fun startRendering() {
+        updateJob =
+            SupervisorJob(
+                coroutineScope.launch() {
+                    gltfAnchorModel =
+                        renderSession.createGltfResourceAsync("models/xyzArrows.glb").await()
+                    planeRenderer.renderedPlanes.collect { attachInteractableComponents(it) }
+                }
+            )
+    }
+
+    internal fun stopRendering() {
+        updateJob.complete()
+        clearRenderedAnchors()
+    }
+
+    private fun clearRenderedAnchors() {
+        for (anchor in renderedAnchors) {
+            anchor.entity.dispose()
+        }
+        renderedAnchors.clear()
+    }
+
+    private fun attachInteractableComponents(planeModels: Collection<PlaneModel>) {
+        for (planeModel in planeModels) {
+            if (planeModel.entity.getComponents().isEmpty()) {
+                planeModel.entity.addComponent(
+                    InteractableComponent.create(renderSession, activity.mainExecutor) { event ->
+                        if (event.action.equals(InputEvent.ACTION_DOWN)) {
+                            val up =
+                                renderSession.spatialUser.head?.getActivitySpacePose()?.up
+                                    ?: Vector3.Up
+                            val perceptionRayPose =
+                                renderSession.activitySpace.transformPoseTo(
+                                    Pose(
+                                        event.origin,
+                                        Quaternion.fromLookTowards(event.direction, up)
+                                    ),
+                                    renderSession.perceptionSpace,
+                                )
+                            val perceptionRay =
+                                Ray(perceptionRayPose.translation, perceptionRayPose.forward)
+                            hitTest(session, perceptionRay)
+                                .firstOrNull {
+                                    // TODO(b/372054517): Re-enable creating anchors on Unknown
+                                    // planes once we can
+                                    // support rendering them.
+                                    (it.trackable as? Plane)?.state?.value?.label !=
+                                        Plane.Label.Unknown
+                                }
+                                ?.let { hitResult ->
+                                    try {
+                                        when (
+                                            val anchorResult =
+                                                Anchor.create(session, hitResult.hitPose)
+                                        ) {
+                                            is AnchorCreateSuccess ->
+                                                renderedAnchors.add(
+                                                    createAnchorModel(anchorResult.anchor)
+                                                )
+                                            is AnchorCreateResourcesExhausted -> {}
+                                        }
+                                    } catch (e: IllegalStateException) {
+                                        Log.e(
+                                            activity::class.simpleName,
+                                            "Failed to create anchor: ${e.message}"
+                                        )
+                                    }
+                                }
+                        }
+                    }
+                )
+            }
+        }
+    }
+
+    private fun createAnchorModel(anchor: Anchor): AnchorModel {
+        val entity = renderSession.createGltfEntity(gltfAnchorModel, Pose())
+        entity.setScale(.1f)
+        val renderJob =
+            coroutineScope.launch(updateJob) {
+                anchor.state.collect { state ->
+                    if (state.trackingState == TrackingState.Tracking) {
+                        entity.setPose(
+                            renderSession.perceptionSpace.transformPoseTo(
+                                state.pose,
+                                renderSession.activitySpace
+                            )
+                        )
+                    } else if (state.trackingState == TrackingState.Stopped) {
+                        entity.setHidden(true)
+                    }
+                }
+            }
+        return AnchorModel(anchor.hashCode(), anchor.state, entity, renderJob)
+    }
+}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneModel.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneModel.kt
new file mode 100644
index 0000000..7fb4fd8
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneModel.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.xr.arcore.apps.whitebox.helloar.rendering
+
+import androidx.xr.arcore.Plane
+import androidx.xr.scenecore.Entity
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.StateFlow
+
+/** Represents a rendered plane model. */
+data class PlaneModel(
+    val id: Int,
+    val type: Plane.Type,
+    val stateFlow: StateFlow<Plane.State>,
+    internal val entity: Entity,
+    internal val renderJob: Job?,
+) {}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneRenderer.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneRenderer.kt
new file mode 100644
index 0000000..b60ab49
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/helloar/rendering/PlaneRenderer.kt
@@ -0,0 +1,182 @@
+/*
+ * 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.xr.arcore.apps.whitebox.helloar.rendering
+
+import android.app.Activity
+import android.content.res.Resources
+import android.graphics.Color
+import android.view.View
+import android.widget.TextView
+import androidx.xr.arcore.Plane
+import androidx.xr.arcore.TrackingState
+import androidx.xr.runtime.Session
+import androidx.xr.runtime.math.Pose
+import androidx.xr.runtime.math.Quaternion
+import androidx.xr.runtime.math.Vector2
+import androidx.xr.runtime.math.Vector3
+import androidx.xr.scenecore.Dimensions
+import androidx.xr.scenecore.PanelEntity
+import androidx.xr.scenecore.PixelDimensions
+import androidx.xr.scenecore.Session as JxrCoreSession
+import kotlinx.coroutines.CompletableJob
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+/** Class that keeps track of planes rendered as GLTF models in a SceneCore session. */
+internal class PlaneRenderer(
+    val session: Session,
+    val renderSession: JxrCoreSession,
+    val coroutineScope: CoroutineScope,
+) {
+
+    private val _renderedPlanes: MutableStateFlow<List<PlaneModel>> =
+        MutableStateFlow(mutableListOf<PlaneModel>())
+    internal val renderedPlanes: StateFlow<Collection<PlaneModel>> = _renderedPlanes.asStateFlow()
+
+    private lateinit var updateJob: CompletableJob
+
+    internal fun startRendering() {
+        updateJob =
+            SupervisorJob(
+                coroutineScope.launch { Plane.subscribe(session).collect { updatePlaneModels(it) } }
+            )
+    }
+
+    internal fun stopRendering() {
+        updateJob.complete()
+        _renderedPlanes.value = emptyList<PlaneModel>()
+    }
+
+    private fun updatePlaneModels(planes: Collection<Plane>) {
+        val planesToRender = _renderedPlanes.value.toMutableList()
+        // Create renderers for new planes.
+        for (plane in planes) {
+            if (_renderedPlanes.value.none { it.id == plane.hashCode() }) {
+                addPlaneModel(plane, planesToRender)
+            }
+        }
+        // Stop rendering dropped planes.
+        for (renderedPlane in _renderedPlanes.value) {
+            if (planes.none { it.hashCode() == renderedPlane.id }) {
+                removePlaneModel(renderedPlane, planesToRender)
+            }
+        }
+        // Emit to notify collectors that collection has been updated.
+        _renderedPlanes.value = planesToRender
+    }
+
+    private fun addPlaneModel(plane: Plane, planesToRender: MutableList<PlaneModel>) {
+        val view = createPanelDebugViewUsingCompose(plane, renderSession.activity)
+        val entity = createPlanePanelEntity(plane, view)
+        // The counter starts at max to trigger the resize on the first update loop since emulators
+        // only
+        // update their static planes once.
+        var counter = PANEL_RESIZE_UPDATE_COUNT
+        // Make the render job a child of the update job so it completes when the parent completes.
+        val renderJob =
+            coroutineScope.launch(updateJob) {
+                plane.state.collect { state ->
+                    if (state.trackingState == TrackingState.Tracking) {
+                        if (state.label == Plane.Label.Unknown) {
+                            entity.setHidden(true)
+                        } else {
+                            entity.setHidden(false)
+                            counter++
+                            entity.setPose(
+                                renderSession.perceptionSpace
+                                    .transformPoseTo(state.centerPose, renderSession.activitySpace)
+                                    // Planes are X-Y while Panels are X-Z, so we need to rotate the
+                                    // X-axis by -90
+                                    // degrees to align them.
+                                    .compose(PANEL_TO_PLANE_ROTATION)
+                            )
+
+                            updateViewText(view, plane, state)
+                            if (counter > PANEL_RESIZE_UPDATE_COUNT) {
+                                val panelExtentsInPixels = convertMetersToPixels(state.extents)
+                                entity.setPixelDimensions(
+                                    PixelDimensions(
+                                        width = panelExtentsInPixels.x.toInt(),
+                                        height = panelExtentsInPixels.y.toInt(),
+                                    )
+                                )
+                                counter = 0
+                            }
+                        }
+                    } else if (state.trackingState == TrackingState.Stopped) {
+                        entity.setHidden(true)
+                    }
+                }
+            }
+
+        planesToRender.add(PlaneModel(plane.hashCode(), plane.type, plane.state, entity, renderJob))
+    }
+
+    private fun createPlanePanelEntity(plane: Plane, view: View): PanelEntity {
+        return renderSession.createPanelEntity(
+            view,
+            Dimensions(320f, 320f),
+            Dimensions(1f, 1f, 1f),
+            plane.hashCode().toString(),
+            plane.state.value.centerPose,
+        )
+    }
+
+    private fun createPanelDebugViewUsingCompose(plane: Plane, activity: Activity): View {
+        val view = TextView(activity.applicationContext)
+        view.text = "Plane: ${plane.hashCode()}"
+        view.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM)
+        view.setBackgroundColor(Color.WHITE)
+        return view
+    }
+
+    private fun updateViewText(view: View, plane: Plane, state: Plane.State) {
+        val textView = view as TextView
+        textView.setBackgroundColor(convertPlaneLabelToColor(state.label))
+        textView.text = "Plane: ${plane.hashCode()}"
+    }
+
+    private fun convertPlaneLabelToColor(label: Plane.Label): Int =
+        when (label) {
+            Plane.Label.Wall -> Color.GREEN
+            Plane.Label.Floor -> Color.BLUE
+            Plane.Label.Ceiling -> Color.YELLOW
+            Plane.Label.Table -> Color.MAGENTA
+            // Planes with Unknown Label are currently not rendered.
+            else -> Color.RED
+        }
+
+    private fun convertMetersToPixels(input: Vector2): Vector2 = input * PX_PER_METER
+
+    private fun removePlaneModel(planeModel: PlaneModel, planesToRender: MutableList<PlaneModel>) {
+        planeModel.renderJob?.cancel()
+        planeModel.entity.dispose()
+        planesToRender.remove(planeModel)
+    }
+
+    private companion object {
+        private val PX_PER_METER = Resources.getSystem().displayMetrics.density * 1111.11f
+        private val PANEL_TO_PLANE_ROTATION =
+            Pose(Vector3(), Quaternion.fromEulerAngles(-90f, 0f, 0f))
+        private const val PANEL_RESIZE_UPDATE_COUNT = 50
+    }
+}
diff --git a/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/persistentanchors/PersistentAnchorsActivity.kt b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/persistentanchors/PersistentAnchorsActivity.kt
new file mode 100644
index 0000000..58a806f
--- /dev/null
+++ b/xr/arcore/integration-tests/whitebox/src/main/kotlin/androidx/xr/arcore/apps/whitebox/persistentanchors/PersistentAnchorsActivity.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.xr.arcore.apps.whitebox.persistentanchors
+
+import android.app.Activity
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.ViewModelStoreOwner
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.lifecycle.setViewTreeViewModelStoreOwner
+import androidx.savedstate.SavedStateRegistryOwner
+import androidx.savedstate.setViewTreeSavedStateRegistryOwner
+import androidx.xr.arcore.Anchor
+import androidx.xr.arcore.AnchorCreateSuccess
+import androidx.xr.arcore.apps.whitebox.common.BackToMainActivityButton
+import androidx.xr.arcore.apps.whitebox.common.SessionLifecycleHelper
+import androidx.xr.runtime.Session
+import androidx.xr.runtime.math.Pose
+import androidx.xr.runtime.math.Vector3
+import androidx.xr.scenecore.Dimensions
+import androidx.xr.scenecore.Entity
+import androidx.xr.scenecore.Session as JxrCoreSession
+import java.util.UUID
+import kotlin.collections.List
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+
+/** Activity to test the Persistent Anchor APIs. */
+class PersistentAnchorsActivity : ComponentActivity() {
+
+    private lateinit var session: Session
+    private lateinit var sessionHelper: SessionLifecycleHelper
+    private lateinit var jxrCoreSession: JxrCoreSession
+    private lateinit var movableEntity: Entity
+    private val movableEntityOffset = Pose(Vector3(0f, 0f, -2.0f))
+    private val uuids = MutableStateFlow<List<UUID>>(emptyList())
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        sessionHelper =
+            SessionLifecycleHelper(
+                onCreateCallback = {
+                    session = it
+                    jxrCoreSession = JxrCoreSession.create(this)
+                    createTargetPanel()
+                    setContent { MainPanel() }
+                },
+                onResumeCallback = { onResumeCallback() },
+            )
+        lifecycle.addObserver(sessionHelper)
+    }
+
+    private fun createTargetPanel() {
+        val composeView = ComposeView(this)
+        composeView.setContent { TargetPanel() }
+        configureComposeView(composeView, this)
+        movableEntity =
+            jxrCoreSession.createPanelEntity(
+                composeView,
+                Dimensions(640f, 640f),
+                Dimensions(1f, 1f, 1f),
+                "movableEntity",
+                movableEntityOffset,
+            )
+        movableEntity.setParent(jxrCoreSession.activitySpace)
+    }
+
+    private fun onResumeCallback() {
+        lifecycleScope.launch {
+            // First load will fail, so we launch a second load after a delay which should succeed.
+            uuids.emit(Anchor.getPersistedAnchorUuids(session))
+            delay(2.seconds)
+            uuids.emit(Anchor.getPersistedAnchorUuids(session))
+        }
+        lifecycleScope.launch { session.state.collect { updatePlaneEntity() } }
+    }
+
+    private fun updatePlaneEntity() {
+        jxrCoreSession.spatialUser.head?.let {
+            movableEntity.setPose(
+                it.transformPoseTo(movableEntityOffset, jxrCoreSession.activitySpace)
+            )
+        }
+    }
+
+    private fun configureComposeView(composeView: ComposeView, activity: Activity) {
+        composeView.setViewCompositionStrategy(
+            ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
+        )
+        composeView.setViewTreeLifecycleOwner(activity as LifecycleOwner)
+        composeView.setViewTreeViewModelStoreOwner(activity as ViewModelStoreOwner)
+        composeView.setViewTreeSavedStateRegistryOwner(activity as SavedStateRegistryOwner)
+    }
+
+    @Composable
+    private fun MainPanel() {
+        val uuidsState = uuids.collectAsStateWithLifecycle()
+
+        Column(
+            modifier =
+                Modifier.background(color = Color.White)
+                    .fillMaxHeight()
+                    .fillMaxWidth()
+                    .padding(horizontal = 20.dp)
+        ) {
+            BackToMainActivityButton()
+            Text(modifier = Modifier.padding(top = 20.dp), text = "Persisted anchors:")
+            for (uuid in uuidsState.value) {
+                Row(modifier = Modifier.fillMaxWidth().padding(vertical = 20.dp)) {
+                    Text(text = "UUID: $uuid", fontSize = 24.sp)
+                    Button(onClick = { loadAnchor(uuid) }) { Text("Load anchor") }
+                    Button(onClick = { unpersistAnchor(uuid) }) { Text("Unpersist anchor") }
+                }
+            }
+        }
+    }
+
+    @Composable
+    private fun TargetPanel() {
+        Column(
+            modifier =
+                Modifier.background(color = Color.White)
+                    .fillMaxHeight()
+                    .fillMaxWidth()
+                    .padding(horizontal = 20.dp),
+            verticalArrangement = Arrangement.Center,
+        ) {
+            Button(onClick = { addAnchor() }) { Text(text = "Add anchor", fontSize = 38.sp) }
+        }
+    }
+
+    private fun addAnchor() {
+        val anchorPose =
+            jxrCoreSession.activitySpace.transformPoseTo(
+                movableEntity.getPose(),
+                jxrCoreSession.perceptionSpace,
+            )
+        val anchor = (Anchor.create(session, anchorPose) as AnchorCreateSuccess).anchor
+        createAnchorPanel(anchor)
+    }
+
+    private fun createAnchorPanel(anchor: Anchor) {
+        val composeView = ComposeView(this)
+        configureComposeView(composeView, this)
+        val anchorEntity = jxrCoreSession.createAnchorEntity(anchor)
+        val panelEntity =
+            jxrCoreSession.createPanelEntity(
+                composeView,
+                Dimensions(640f, 640f),
+                Dimensions(1f, 1f, 1f),
+                "anchorEntity ${anchor.hashCode()}",
+                Pose(),
+            )
+        panelEntity.setParent(anchorEntity)
+        composeView.setContent { AnchorPanel(anchor, panelEntity) }
+    }
+
+    @Composable
+    private fun AnchorPanel(anchor: Anchor, entity: Entity) {
+        val anchorState = anchor.state.collectAsStateWithLifecycle()
+        Column(
+            modifier =
+                Modifier.background(color = Color.White)
+                    .fillMaxHeight()
+                    .fillMaxWidth()
+                    .padding(horizontal = 20.dp),
+            verticalArrangement = Arrangement.Center,
+        ) {
+            Text(
+                modifier = Modifier.padding(top = 10.dp),
+                text = "Tracking State: ${anchorState.value.trackingState}",
+                fontSize = 32.sp,
+            )
+            Button(modifier = Modifier.padding(top = 10.dp), onClick = { persistAnchor(anchor) }) {
+                Text(text = "Persist anchor", fontSize = 32.sp)
+            }
+            Button(
+                modifier = Modifier.padding(top = 10.dp),
+                onClick = { deleteEntity(anchor, entity) }
+            ) {
+                Text(text = "Delete anchor", fontSize = 32.sp)
+            }
+        }
+    }
+
+    private fun persistAnchor(anchor: Anchor) {
+        lifecycleScope.launch {
+            try {
+                anchor.persist()
+                uuids.emit(Anchor.getPersistedAnchorUuids(session))
+            } catch (e: RuntimeException) {
+                Log.e("ARCore", "Error persisting anchor: ${e.message}")
+            }
+        }
+    }
+
+    private fun deleteEntity(anchor: Anchor, entity: Entity) {
+        entity.dispose()
+        anchor.detach()
+    }
+
+    private fun unpersistAnchor(uuid: UUID) {
+        Anchor.unpersist(session, uuid)
+        lifecycleScope.launch { uuids.emit(uuids.value - uuid) }
+    }
+
+    private fun loadAnchor(uuid: UUID) {
+        val anchor = (Anchor.load(session, uuid) as AnchorCreateSuccess).anchor
+        lifecycleScope.launch {
+            // We need to wait until the anchor is tracked before querying its pose.
+            delay(1.seconds)
+            createAnchorPanel(anchor)
+        }
+    }
+}
diff --git a/xr/assets/README.md b/xr/assets/README.md
new file mode 100644
index 0000000..01e95eb
--- /dev/null
+++ b/xr/assets/README.md
@@ -0,0 +1,8 @@
+# Jetpack XR Assets
+
+This library contains a collection of assets used across the Jetpack XR
+libraries for testing/sample purposes. Additional assets may not be added in
+other repositories to avoid file duplication.
+
+All files in this directory were created for this purpose and are released
+under the terms of the Apache 2.0 license.
diff --git a/xr/assets/build.gradle b/xr/assets/build.gradle
new file mode 100644
index 0000000..0116f70
--- /dev/null
+++ b/xr/assets/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+/**
+ * This file was created using the `create_project.py` script located in the
+ * `<AndroidX root>/development/project-creator` directory.
+ *
+ * Please use that script when creating a new project, rather than copying an existing project and
+ * modifying its settings.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    namespace = "androidx.xr.assets"
+}
+
+androidx {
+    name = "XR Assets"
+    type = LibraryType.INTERNAL_TEST_LIBRARY
+    inceptionYear = "2024"
+    description = "Collection of assets for use across the XR libraries."
+}
diff --git a/xr/assets/src/main/assets/models/xyzArrows.glb b/xr/assets/src/main/assets/models/xyzArrows.glb
new file mode 100644
index 0000000..c43f3e7
--- /dev/null
+++ b/xr/assets/src/main/assets/models/xyzArrows.glb
Binary files differ
diff --git a/xr/compose/material3/material3/build.gradle b/xr/compose/material3/material3/build.gradle
index 0cad526..ec48d06 100644
--- a/xr/compose/material3/material3/build.gradle
+++ b/xr/compose/material3/material3/build.gradle
@@ -42,7 +42,7 @@
     implementation(project(":compose:material3:material3"))
     implementation(project(":compose:material3:material3-adaptive-navigation-suite"))
 
-    implementation(project(":xr:compose:compose"))
+    implementation("androidx.xr.compose:compose:1.0.0-alpha01")
 }
 
 android {