Merge "Revert "Fix regression b/276792587"" into androidx-main
diff --git a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityReportFullyDrawnTest.kt b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityReportFullyDrawnTest.kt
index a091c94..1b0c974 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityReportFullyDrawnTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityReportFullyDrawnTest.kt
@@ -16,13 +16,14 @@
 
 package androidx.activity
 
+import android.view.View
 import androidx.test.core.app.ActivityScenario
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.testutils.withActivity
+import androidx.testutils.withUse
 import leakcanary.DetectLeaksAfterTestSuccess
 import org.junit.Rule
-import androidx.testutils.withUse
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -44,6 +45,21 @@
             }
         }
     }
+
+    @Test
+    fun testReportFullyDrawnRecreate() {
+        val activity = ActivityScenario.launch(ReportFullyDrawnActivity::class.java)
+        activity.withActivity {
+            setContentView(
+                View(this)
+            )
+        }
+        activity.recreate().withActivity {
+            setContentView(
+                View(this)
+            )
+        }
+    }
 }
 
 class ReportFullyDrawnActivity : ComponentActivity()
diff --git a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
index 0028456..db3b9b3 100644
--- a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
+++ b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
@@ -172,7 +172,7 @@
                 }
             });
 
-    private final ReportFullyDrawnExecutor mReportFullyDrawnExecutor = createFullyDrawnExecutor();
+    final ReportFullyDrawnExecutor mReportFullyDrawnExecutor = createFullyDrawnExecutor();
 
     @NonNull
     final FullyDrawnReporter mFullyDrawnReporter = new FullyDrawnReporter(
@@ -314,6 +314,7 @@
                     if (!isChangingConfigurations()) {
                         getViewModelStore().clear();
                     }
+                    mReportFullyDrawnExecutor.activityDestroyed();
                 }
             }
         });
@@ -1150,6 +1151,8 @@
 
     private interface ReportFullyDrawnExecutor extends Executor {
         void viewCreated(@NonNull View view);
+
+        void activityDestroyed();
     }
 
     static class ReportFullyDrawnExecutorApi1 implements ReportFullyDrawnExecutor {
@@ -1159,6 +1162,10 @@
         public void viewCreated(@NonNull View view) {
         }
 
+        @Override
+        public void activityDestroyed() {
+        }
+
         /**
          * Called when we want to execute runnable that might call
          * {@link ComponentActivity#reportFullyDrawn()}.
@@ -1191,6 +1198,12 @@
             }
         }
 
+        @Override
+        public void activityDestroyed() {
+            getWindow().getDecorView().removeCallbacks(this);
+            getWindow().getDecorView().getViewTreeObserver().removeOnDrawListener(this);
+        }
+
         /**
          * Called when we want to execute runnable that might call
          * {@link ComponentActivity#reportFullyDrawn()}.
diff --git a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
index 40063fb..af8360c 100644
--- a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
+++ b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateCall.kt
@@ -17,8 +17,7 @@
 package androidx.appactions.interaction.capabilities.communication
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
@@ -27,8 +26,7 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.CALL_TYPE_SPEC
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.PARTICIPANT_TYPE_SPEC
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.Call
 import androidx.appactions.interaction.capabilities.core.values.Call.CallFormat
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
@@ -43,20 +41,20 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(CreateCall.Property::class.java)
-        .setArgument(CreateCall.Argument::class.java, CreateCall.Argument::Builder)
+        .setDescriptor(CreateCall.Properties::class.java)
+        .setArguments(CreateCall.Arguments::class.java, CreateCall.Arguments::Builder)
         .setOutput(CreateCall.Output::class.java)
         .bindOptionalParameter(
             "call.callFormat",
             { property -> Optional.ofNullable(property.callFormat) },
-            CreateCall.Argument.Builder::setCallFormat,
+            CreateCall.Arguments.Builder::setCallFormat,
             TypeConverters.CALL_FORMAT_PARAM_VALUE_CONVERTER,
             TypeConverters.CALL_FORMAT_ENTITY_CONVERTER
         )
         .bindRepeatedParameter(
             "call.participant",
             { property -> Optional.ofNullable(property.participant) },
-            CreateCall.Argument.Builder::setParticipantList,
+            CreateCall.Arguments.Builder::setParticipantList,
             ParticipantValue.PARAM_VALUE_CONVERTER,
             EntityConverter.of(PARTICIPANT_TYPE_SPEC)
         )
@@ -75,22 +73,22 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class CreateCall private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
-        >(ACTION_SPEC) {
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
+            >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             // TODO(b/268369632): No-op remove empty property builder after Property is removed.
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property
+    class Properties
     internal constructor(
-        val callFormat: TypeProperty<CallFormat>?,
-        val participant: TypeProperty<Participant>?
+        val callFormat: Property<CallFormat>?,
+        val participant: Property<Participant>?
     ) {
         override fun toString(): String {
             return "Property(callFormat=$callFormat, participant=$participant)"
@@ -100,7 +98,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (callFormat != other.callFormat) return false
             if (participant != other.participant) return false
@@ -115,32 +113,32 @@
         }
 
         class Builder {
-            private var callFormat: TypeProperty<CallFormat>? = null
+            private var callFormat: Property<CallFormat>? = null
 
-            private var participant: TypeProperty<Participant>? = null
+            private var participant: Property<Participant>? = null
 
-            fun setCallFormat(callFormat: TypeProperty<CallFormat>): Builder = apply {
+            fun setCallFormat(callFormat: Property<CallFormat>): Builder = apply {
                 this.callFormat = callFormat
             }
 
-            fun build(): Property = Property(callFormat, participant)
+            fun build(): Properties = Properties(callFormat, participant)
         }
     }
 
-    class Argument
+    class Arguments
     internal constructor(
         val callFormat: CallFormat?,
         val participantList: List<ParticipantValue>,
     ) {
         override fun toString(): String {
-            return "Argument(callFormat=$callFormat, participantList=$participantList)"
+            return "Arguments(callFormat=$callFormat, participantList=$participantList)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (callFormat != other.callFormat) return false
             if (participantList != other.participantList) return false
@@ -154,7 +152,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var callFormat: CallFormat? = null
             private var participantList: List<ParticipantValue> = mutableListOf()
 
@@ -166,7 +164,7 @@
                 this.participantList = participantList
             }
 
-            override fun build(): Argument = Argument(callFormat, participantList)
+            override fun build(): Arguments = Arguments(callFormat, participantList)
         }
     }
 
@@ -238,7 +236,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
index 664578f..6f428e1 100644
--- a/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
+++ b/appactions/interaction/interaction-capabilities-communication/src/main/java/androidx/appactions/interaction/capabilities/communication/CreateMessage.kt
@@ -17,8 +17,7 @@
 package androidx.appactions.interaction.capabilities.communication
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
@@ -28,8 +27,7 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.RECIPIENT_TYPE_SPEC
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.Message
 import androidx.appactions.interaction.capabilities.core.values.properties.Recipient
@@ -43,20 +41,20 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(CreateMessage.Property::class.java)
-        .setArgument(CreateMessage.Argument::class.java, CreateMessage.Argument::Builder)
+        .setDescriptor(CreateMessage.Properties::class.java)
+        .setArguments(CreateMessage.Arguments::class.java, CreateMessage.Arguments::Builder)
         .setOutput(CreateMessage.Output::class.java)
         .bindRepeatedParameter(
             "message.recipient",
             { property -> Optional.ofNullable(property.recipient) },
-            CreateMessage.Argument.Builder::setRecipientList,
+            CreateMessage.Arguments.Builder::setRecipientList,
             RecipientValue.PARAM_VALUE_CONVERTER,
             EntityConverter.of(RECIPIENT_TYPE_SPEC)
         )
         .bindOptionalParameter(
             "message.text",
             { property -> Optional.ofNullable(property.messageText) },
-            CreateMessage.Argument.Builder::setMessageText,
+            CreateMessage.Arguments.Builder::setMessageText,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER
         )
@@ -75,22 +73,22 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class CreateMessage private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
-        >(ACTION_SPEC) {
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
+            >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             // TODO(b/268369632): No-op remove empty property builder after Property is removed.
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property
+    class Properties
     internal constructor(
-        val recipient: TypeProperty<Recipient>?,
-        val messageText: TypeProperty<StringValue>?
+        val recipient: Property<Recipient>?,
+        val messageText: Property<StringValue>?
     ) {
         override fun toString(): String {
             return "Property(recipient=$recipient, messageText=$messageText)"
@@ -100,7 +98,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (recipient != other.recipient) return false
             if (messageText != other.messageText) return false
@@ -115,32 +113,32 @@
         }
 
         class Builder {
-            private var recipient: TypeProperty<Recipient>? = null
-            private var messageText: TypeProperty<StringValue>? = null
+            private var recipient: Property<Recipient>? = null
+            private var messageText: Property<StringValue>? = null
 
-            fun setRecipient(recipient: TypeProperty<Recipient>): Builder = apply {
+            fun setRecipient(recipient: Property<Recipient>): Builder = apply {
                 this.recipient = recipient
             }
 
-            fun setMessageText(messageText: TypeProperty<StringValue>): Builder = apply {
+            fun setMessageText(messageText: Property<StringValue>): Builder = apply {
                 this.messageText = messageText
             }
 
-            fun build(): Property = Property(recipient, messageText)
+            fun build(): Properties = Properties(recipient, messageText)
         }
     }
 
-    class Argument
+    class Arguments
     internal constructor(val recipientList: List<RecipientValue>, val messageText: String?) {
         override fun toString(): String {
-            return "Argument(recipient=$recipientList, messageTextList=$messageText)"
+            return "Arguments(recipient=$recipientList, messageTextList=$messageText)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (recipientList != other.recipientList) return false
             if (messageText != other.messageText) return false
@@ -154,7 +152,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var recipientList: List<RecipientValue> = mutableListOf()
             private var messageText: String? = null
 
@@ -166,7 +164,7 @@
                 this.messageText = messageTextList
             }
 
-            override fun build(): Argument = Argument(recipientList, messageText)
+            override fun build(): Arguments = Arguments(recipientList, messageText)
         }
     }
 
@@ -239,7 +237,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/properties/ItemListElement.kt
similarity index 72%
copy from bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
copy to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/properties/ItemListElement.kt
index 84d9567..3be1e5f 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/properties/ItemListElement.kt
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.bluetooth.integration.testapp.data
+package androidx.appactions.builtintypes.properties
 
-import android.os.ParcelUuid
+import androidx.appactions.builtintypes.types.ListItem
 
-object SampleAdvertiseData {
-    val testUUID: ParcelUuid =
-        ParcelUuid.fromString("00000000-0000-0000-0000-000000000001")
-}
+class ItemListElement(asListItem: ListItem) {
+    @get:JvmName("asListItem")
+    val asListItem: ListItem = asListItem
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/CalendarEvent.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/CalendarEvent.kt
index e5cf454..858de50 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/CalendarEvent.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/CalendarEvent.kt
@@ -40,7 +40,7 @@
         fun setEndDate(endDate: EndDate?): Self
         fun setEndDate(value: LocalDate): Self
         fun addAttendee(attendee: Attendee): Self
-        fun addAllAttendee(value: Iterable<Attendee>): Self
+        fun addAttendees(value: List<Attendee>): Self
 
         override fun build(): CalendarEvent
     }
@@ -54,7 +54,8 @@
     private var endDate: EndDate? = null
     private var attendeeList = mutableListOf<Attendee>()
 
-    override fun build() = CalendarEventImpl(identifier, name, startDate, endDate, attendeeList)
+    override fun build() =
+        CalendarEventImpl(identifier, name, startDate, endDate, attendeeList.toList())
 
     override fun setStartDate(startDate: StartDate?): CalendarEventBuilderImpl = apply {
         this.startDate = startDate
@@ -76,7 +77,7 @@
         attendeeList.add(attendee)
     }
 
-    override fun addAllAttendee(value: Iterable<Attendee>): CalendarEventBuilderImpl = apply {
+    override fun addAttendees(value: List<Attendee>): CalendarEventBuilderImpl = apply {
         attendeeList.addAll(value)
     }
 
@@ -104,5 +105,5 @@
             .setName(name)
             .setStartDate(startDate)
             .setEndDate(endDate)
-            .addAllAttendee(attendeeList)
+            .addAttendees(attendeeList)
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ItemList.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ItemList.kt
new file mode 100644
index 0000000..ff70802
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ItemList.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.Name
+import androidx.appactions.builtintypes.properties.ItemListElement
+
+interface ItemList : Thing {
+    val itemListElements: List<ItemListElement>
+    override fun toBuilder(): Builder<*>
+
+    companion object {
+        @JvmStatic
+        fun Builder(): Builder<*> = ItemListBuilderImpl()
+    }
+
+    interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
+        fun addItemListElements(itemListElements: List<ItemListElement>): Self
+        fun addItemListElement(itemListElement: ItemListElement): Self
+        fun addItemListElement(listItem: ListItem): Self
+        override fun build(): ItemList
+    }
+}
+
+private class ItemListBuilderImpl : ItemList.Builder<ItemListBuilderImpl> {
+    private var identifier: String? = null
+    private var name: Name? = null
+    private var itemListElements = mutableListOf<ItemListElement>()
+
+    override fun build() = ItemListImpl(identifier, name, itemListElements.toList())
+
+    override fun addItemListElements(itemListElements: List<ItemListElement>): ItemListBuilderImpl =
+        apply {
+            this.itemListElements.addAll(itemListElements)
+        }
+
+    override fun addItemListElement(itemListElement: ItemListElement): ItemListBuilderImpl = apply {
+        itemListElements.add(itemListElement)
+    }
+
+    override fun addItemListElement(listItem: ListItem): ItemListBuilderImpl = apply {
+        itemListElements.add(ItemListElement(listItem))
+    }
+
+    override fun setIdentifier(text: String?): ItemListBuilderImpl = apply {
+        identifier = text
+    }
+
+    override fun setName(text: String): ItemListBuilderImpl = apply {
+        name = Name(text)
+    }
+
+    override fun setName(name: Name?): ItemListBuilderImpl = apply {
+        this.name = name
+    }
+
+    override fun clearName(): ItemListBuilderImpl = apply { name = null }
+}
+
+private class ItemListImpl(
+    override val identifier: String?,
+    override val name: Name?,
+    override val itemListElements: List<ItemListElement>
+) : ItemList {
+    override fun toBuilder(): ItemList.Builder<*> =
+        ItemListBuilderImpl()
+            .setIdentifier(identifier)
+            .setName(name)
+            .addItemListElements(itemListElements)
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ListItem.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ListItem.kt
new file mode 100644
index 0000000..bff0c25
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/ListItem.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.builtintypes.types
+
+import androidx.appactions.builtintypes.properties.Name
+
+interface ListItem : Thing {
+    override fun toBuilder(): Builder<*>
+
+    companion object {
+        @JvmStatic
+        fun Builder(): Builder<*> = ListItemBuilderImpl()
+    }
+
+    interface Builder<Self : Builder<Self>> : Thing.Builder<Self> {
+        override fun build(): ListItem
+    }
+}
+
+private class ListItemBuilderImpl : ListItem.Builder<ListItemBuilderImpl> {
+    private var identifier: String? = null
+    private var name: Name? = null
+    override fun build() = ListItemImpl(identifier, name)
+
+    override fun setIdentifier(text: String?): ListItemBuilderImpl = apply {
+        identifier = text
+    }
+
+    override fun setName(text: String): ListItemBuilderImpl = apply {
+        name = Name(text)
+    }
+
+    override fun setName(name: Name?): ListItemBuilderImpl = apply {
+        this.name = name
+    }
+
+    override fun clearName(): ListItemBuilderImpl = apply { name = null }
+}
+
+private class ListItemImpl(
+    override val identifier: String?,
+    override val name: Name?
+) : ListItem {
+    override fun toBuilder(): ListItem.Builder<*> =
+        ListItemBuilderImpl().setIdentifier(identifier).setName(name)
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/Message.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/Message.kt
index 2b1de7c..f5d044d 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/Message.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/builtintypes/types/Message.kt
@@ -32,7 +32,7 @@
     interface Builder<Self : Builder<Self>> : Thing.Builder<Self>, CreativeWork.Builder<Self> {
         fun addRecipient(person: Person): Self
         fun addRecipient(recipient: Recipient): Self
-        fun addAllRecipient(value: Iterable<Recipient>): Self
+        fun addRecipients(value: List<Recipient>): Self
 
         override fun build(): Message
     }
@@ -55,7 +55,7 @@
         recipientList.add(recipient)
     }
 
-    override fun addAllRecipient(value: Iterable<Recipient>): MessageBuilderImpl = apply {
+    override fun addRecipients(value: List<Recipient>): MessageBuilderImpl = apply {
         recipientList.addAll(value)
     }
 
@@ -83,5 +83,5 @@
             .setIdentifier(identifier)
             .setName(name)
             .setText(text)
-            .addAllRecipient(recipientList)
+            .addRecipients(recipientList)
 }
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.kt
index 42bd9f4..34b6889 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.kt
@@ -16,18 +16,32 @@
 
 package androidx.appactions.interaction.capabilities.core
 
+import androidx.annotation.RestrictTo
+import androidx.concurrent.futures.await
+
 /**
  * An interface of executing the action.
  *
  * Actions are executed asynchronously using Kotlin coroutines.
  * For a Future-based solution, see ActionExecutorAsync.
  */
-fun interface ActionExecutor<ArgumentT, OutputT> {
+fun interface ActionExecutor<ArgumentsT, OutputT> {
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY)
+    val uiHandle: Any
+        get() = this
+
     /**
      * Calls to execute the action.
      *
-     * @param argument the argument for this action.
+     * @param arguments the argument for this action.
      * @return the ExecutionResult
      */
-    suspend fun execute(argument: ArgumentT): ExecutionResult<OutputT>
+    suspend fun onExecute(arguments: ArgumentsT): ExecutionResult<OutputT>
 }
+
+internal fun <ArgumentsT, OutputT> ActionExecutorAsync<ArgumentsT, OutputT>.toActionExecutor():
+    ActionExecutor<ArgumentsT, OutputT> = object : ActionExecutor<ArgumentsT, OutputT> {
+    override val uiHandle = this@toActionExecutor
+    override suspend fun onExecute(arguments: ArgumentsT): ExecutionResult<OutputT> =
+        [email protected](arguments).await()
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutorAsync.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutorAsync.kt
index 359cb9f..d7181f6 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutorAsync.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutorAsync.kt
@@ -16,35 +16,15 @@
 
 package androidx.appactions.interaction.capabilities.core
 
-import androidx.annotation.RestrictTo
-import androidx.appactions.interaction.capabilities.core.impl.concurrent.convertToListenableFuture
 import com.google.common.util.concurrent.ListenableFuture
 
 /** An ListenableFuture-based interface of executing an action. */
-fun interface ActionExecutorAsync<ArgumentT, OutputT> {
-    @get:RestrictTo(RestrictTo.Scope.LIBRARY)
-    val uiHandle: Any
-        get() = this
-
+fun interface ActionExecutorAsync<ArgumentsT, OutputT> {
     /**
      * Calls to execute the action.
      *
-     * @param argument the argument for this action.
+     * @param arguments the argument for this action.
      * @return A ListenableFuture containing the ExecutionResult
      */
-    fun execute(argument: ArgumentT): ListenableFuture<ExecutionResult<OutputT>>
-
-    companion object {
-        fun <ArgumentT, OutputT> ActionExecutor<ArgumentT, OutputT>.toActionExecutorAsync():
-            ActionExecutorAsync<ArgumentT, OutputT> =
-            object : ActionExecutorAsync<ArgumentT, OutputT> {
-                override val uiHandle = this@toActionExecutorAsync
-                override fun execute(
-                    argument: ArgumentT,
-                ): ListenableFuture<ExecutionResult<OutputT>> =
-                    convertToListenableFuture("ActionExecutor#execute") {
-                        [email protected](argument)
-                    }
-            }
-    }
+    fun onExecute(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>>
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseSession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseExecutionSession.kt
similarity index 69%
rename from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseSession.kt
rename to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseExecutionSession.kt
index 3e6d9d7..0233d05 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseSession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/BaseExecutionSession.kt
@@ -20,33 +20,33 @@
 import androidx.concurrent.futures.await
 import com.google.common.util.concurrent.ListenableFuture
 
-/** Base interface for Session of all verticals. */
-interface BaseSession<ArgumentT, OutputT> {
+/** Base interface for ExecutionSession of all verticals. */
+interface BaseExecutionSession<ArgumentsT, OutputT> {
     /**
      * Implement any initialization logic.
      *
      * This method is called once, before any other listeners are invoked.
      */
-    fun onInit(initArg: InitArg) {}
+    fun onCreate(sessionContext: SessionContext) {}
 
     /**
      * Called when all arguments are finalized.
      *
-     * @param argument the [ArgumentT] instance containing data for fulfillment.
+     * @param arguments the [ArgumentsT] instance containing data for fulfillment.
      * @return an [ExecutionResult] instance.
      */
-    suspend fun onFinish(argument: ArgumentT): ExecutionResult<OutputT> {
-        return onFinishAsync(argument).await()
+    suspend fun onExecute(arguments: ArgumentsT): ExecutionResult<OutputT> {
+        return onExecuteAsync(arguments).await()
     }
 
     /**
      * Called when all arguments are finalized.
      *
-     * @param argument the Argument instance containing data for fulfillment.
+     * @param arguments the Argument instance containing data for fulfillment.
      * @return a [ListenableFuture] containing an [ExecutionResult] instance.
      */
-    fun onFinishAsync(argument: ArgumentT): ListenableFuture<ExecutionResult<OutputT>> {
-        return Futures.immediateFuture(ExecutionResult.getDefaultInstance())
+    fun onExecuteAsync(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>> {
+        return Futures.immediateFuture(ExecutionResult.Builder<OutputT>().build())
     }
 
     /** Implement any cleanup logic. This method is called some time after the session finishes. */
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
index ae941e4..2075267 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/Capability.kt
@@ -18,32 +18,29 @@
 
 import androidx.annotation.RestrictTo
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
+import androidx.appactions.interaction.capabilities.core.impl.SingleTurnCapabilityImpl
+import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
+import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
+import androidx.appactions.interaction.capabilities.core.impl.task.TaskCapabilityImpl
+import androidx.appactions.interaction.capabilities.core.impl.task.EmptyTaskUpdater
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction
 
 /**
- * <b>Do not implement this interface yourself.</b>
- *
- * <p>A Capability represents some supported App Action that can be given to App Control.
- *
- * <p>Use helper classes provided by the capability library to get instances of this interface.
+ * A Capability represents some supported Built-In-Intent. Register capabilities within an app to
+ * declare support for the capability.
  */
-interface Capability {
-
+abstract class Capability internal constructor(
     /** Returns the unique Id of this capability declaration. */
-    val id: String
-
-    /**
-     * Returns whether or not this capability supports multi-turn task.
-     */
-    val supportsMultiTurnTask: Boolean
+    open val id: String
+) {
 
     /**
      * Returns an app action proto describing how to fulfill this capability.
      *
      * @suppress
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    fun getAppAction(): AppAction
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    abstract val appAction: AppAction
 
     /**
      * Create a new capability session. The capability library doesn't maintain registry of
@@ -52,8 +49,131 @@
      * @suppress
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    fun createSession(
+    abstract fun createSession(
         sessionId: String,
         hostProperties: HostProperties,
     ): CapabilitySession
+
+    /**
+     * An abstract Builder class for Capability.
+     */
+    abstract class Builder<
+        BuilderT :
+        Builder<
+            BuilderT,
+            PropertyT,
+            ArgumentsT,
+            OutputT,
+            ConfirmationT,
+            ExecutionSessionT,
+            >,
+        PropertyT,
+        ArgumentsT,
+        OutputT,
+        ConfirmationT,
+        ExecutionSessionT : BaseExecutionSession<ArgumentsT, OutputT>,
+        > protected constructor(
+        private val actionSpec: ActionSpec<PropertyT, ArgumentsT, OutputT>,
+    ) {
+        private var id: String? = null
+        private var property: PropertyT? = null
+        private var actionExecutor: ActionExecutor<ArgumentsT, OutputT>? = null
+        private var sessionFactory: ExecutionSessionFactory<ExecutionSessionT>? = null
+
+        /**
+         * The SessionBridge object, which is used to normalize Session instances to TaskHandler.
+         * see SessionBridge documentation for more information.
+         *
+         * @suppress
+         */
+        @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        protected open val sessionBridge: SessionBridge<ExecutionSessionT, ConfirmationT>? = null
+
+        @Suppress("UNCHECKED_CAST")
+        fun asBuilder(): BuilderT {
+            return this as BuilderT
+        }
+
+        /**
+         * Sets the Id of the capability being built. The Id should be a non-null string that is
+         * unique among all Capability, and should not change during/across activity lifecycles.
+         */
+        fun setId(id: String): BuilderT = asBuilder().apply {
+            this.id = id
+        }
+
+        /**
+         * Sets the Property instance for this capability. Must be called before {@link
+         * Builder#build}.
+         */
+        protected fun setProperty(property: PropertyT) = asBuilder().apply {
+            this.property = property
+        }
+
+        /**
+         * Sets the ActionExecutor for this capability.
+         *
+         * setExecutionSessionFactory and setExecutor are mutually exclusive, so calling one will
+         * nullify the other.
+         *
+         * This method accepts a coroutine-based ActionExecutor instance. There is also an overload
+         * which accepts the ActionExecutorAsync instead.
+         */
+        fun setExecutor(actionExecutor: ActionExecutor<ArgumentsT, OutputT>) = asBuilder().apply {
+            this.actionExecutor = actionExecutor
+        }
+
+        /**
+         * Sets the ActionExecutorAsync for this capability.
+         *
+         * setExecutionSessionFactory and setExecutor are mutually exclusive, so calling one will
+         * nullify the other.
+         *
+         * This method accepts the ActionExecutorAsync interface which returns a ListenableFuture.
+         */
+        fun setExecutor(
+            actionExecutorAsync: ActionExecutorAsync<ArgumentsT, OutputT>,
+        ) = asBuilder().apply {
+            this.actionExecutor = actionExecutorAsync.toActionExecutor()
+        }
+
+        /**
+         * Sets the SessionBuilder instance which is used to create Session instaces for this
+         * capability.
+         *
+         * [setExecutionSessionFactory] and [setExecutor] are mutually exclusive, so calling one
+         * will nullify the other.
+         */
+        protected open fun setExecutionSessionFactory(
+            sessionFactory: ExecutionSessionFactory<ExecutionSessionT>,
+        ): BuilderT = asBuilder().apply {
+            this.sessionFactory = sessionFactory
+        }
+
+        /** Builds and returns this Capability. */
+        open fun build(): Capability {
+            val checkedId = requireNotNull(id) { "setId must be called before build" }
+            val checkedProperty = requireNotNull(property) { "property must not be null." }
+            if (actionExecutor != null) {
+                return SingleTurnCapabilityImpl(
+                    checkedId,
+                    actionSpec,
+                    checkedProperty,
+                    actionExecutor!!,
+                )
+            } else {
+                val checkedSessionFactory = requireNotNull(sessionFactory) {
+                    "either setExecutor or setExecutionSessionFactory must be called before build"
+                }
+                return TaskCapabilityImpl(
+                    checkedId,
+                    actionSpec,
+                    checkedProperty,
+                    checkedSessionFactory,
+                    sessionBridge!!,
+                    ::EmptyTaskUpdater,
+                )
+            }
+        }
+    }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/CapabilityBuilderBase.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/CapabilityBuilderBase.kt
deleted file mode 100644
index e7cd4ae..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/CapabilityBuilderBase.kt
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core
-
-import androidx.annotation.RestrictTo
-import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync.Companion.toActionExecutorAsync
-import androidx.appactions.interaction.capabilities.core.impl.SingleTurnCapabilityImpl
-import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
-import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
-import androidx.appactions.interaction.capabilities.core.impl.task.TaskCapabilityImpl
-import java.util.function.Supplier
-
-/**
- * An abstract Builder class for Capability.
- */
-abstract class CapabilityBuilderBase<
-    BuilderT :
-    CapabilityBuilderBase<
-        BuilderT,
-        PropertyT,
-        ArgumentT,
-        OutputT,
-        ConfirmationT,
-        SessionUpdaterT,
-        SessionT,>,
-    PropertyT,
-    ArgumentT,
-    OutputT,
-    ConfirmationT,
-    SessionUpdaterT : AbstractTaskUpdater,
-    SessionT : BaseSession<ArgumentT, OutputT>,
-    > protected constructor(
-    private val actionSpec: ActionSpec<PropertyT, ArgumentT, OutputT>,
-) {
-    private var id: String? = null
-    private var property: PropertyT? = null
-    private var actionExecutorAsync: ActionExecutorAsync<ArgumentT, OutputT>? = null
-    private var sessionFactory: SessionFactory<SessionT>? = null
-
-    /**
-     * The SessionBridge object, which is used to normalize Session instances to TaskHandler.
-     * see SessionBridge documentation for more information.
-     *
-     * @suppress
-     */
-    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    protected open val sessionBridge: SessionBridge<SessionT, ConfirmationT>? = null
-
-    /** The supplier of SessionUpdaterT instances. */
-    protected open val sessionUpdaterSupplier: Supplier<SessionUpdaterT>? = null
-
-    @Suppress("UNCHECKED_CAST")
-    fun asBuilder(): BuilderT {
-        return this as BuilderT
-    }
-
-    /**
-     * Sets the Id of the capability being built. The Id should be a non-null string that is unique
-     * among all Capability, and should not change during/across activity lifecycles.
-     */
-    fun setId(id: String): BuilderT = asBuilder().apply {
-        this.id = id
-    }
-
-    /**
-     * Sets the Property instance for this capability. Must be called before {@link
-     * CapabilityBuilderBase.build}.
-     */
-    protected fun setProperty(property: PropertyT) = asBuilder().apply {
-        this.property = property
-    }
-
-    /**
-     * Sets the ActionExecutor for this capability.
-     *
-     * setSessionFactory and setExecutor are mutually exclusive, so calling one will nullify
-     * the other.
-     *
-     * This method accepts a coroutine-based ActionExecutor instance. There is also an overload
-     * which accepts the ActionExecutorAsync instead.
-     */
-    fun setExecutor(actionExecutor: ActionExecutor<ArgumentT, OutputT>) = asBuilder().apply {
-        this.actionExecutorAsync = actionExecutor.toActionExecutorAsync()
-    }
-
-    /**
-     * Sets the ActionExecutorAsync for this capability.
-     *
-     * setSessionFactory and setExecutor are mutually exclusive, so calling one will nullify
-     * the other.
-     *
-     * This method accepts the ActionExecutorAsync interface which returns a ListenableFuture.
-     */
-    fun setExecutor(
-        actionExecutorAsync: ActionExecutorAsync<ArgumentT, OutputT>,
-    ) = asBuilder().apply {
-        this.actionExecutorAsync = actionExecutorAsync
-    }
-
-    /**
-     * Sets the SessionBuilder instance which is used to create Session instaces for this
-     * capability.
-     *
-     * setSessionFactory and setExecutor are mutually exclusive, so calling one will nullify the other.
-     */
-    protected open fun setSessionFactory(
-        sessionFactory: SessionFactory<SessionT>,
-    ): BuilderT = asBuilder().apply {
-        this.sessionFactory = sessionFactory
-    }
-
-    /** Builds and returns this Capability. */
-    open fun build(): Capability {
-        val checkedId = requireNotNull(id, { "setId must be called before build" })
-        val checkedProperty = requireNotNull(property, { "property must not be null." })
-        if (actionExecutorAsync != null) {
-            return SingleTurnCapabilityImpl(
-                checkedId,
-                actionSpec,
-                checkedProperty,
-                actionExecutorAsync!!,
-            )
-        } else {
-            return TaskCapabilityImpl(
-                checkedId,
-                actionSpec,
-                checkedProperty,
-                requireNotNull(
-                    sessionFactory,
-                    { "either setExecutor or setSessionFactory must be called before build" },
-                ),
-                sessionBridge!!,
-                sessionUpdaterSupplier!!,
-            )
-        }
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ConfirmationOutput.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ConfirmationOutput.kt
index e6c907d..c597de3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ConfirmationOutput.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ConfirmationOutput.kt
@@ -46,11 +46,4 @@
         /** Builds and returns the ConfirmationOutput instance. */
         fun build() = ConfirmationOutput(confirmation)
     }
-
-    companion object {
-        /** Returns a default ExecutionResult instance. */
-        @JvmStatic
-        fun <ConfirmationT> getDefaultInstance() = ConfirmationOutput.Builder<ConfirmationT>()
-            .build()
-    }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionResult.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionResult.kt
index 0103cb7..33d22c6 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionResult.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionResult.kt
@@ -21,29 +21,29 @@
  * Class that represents the response after a Capability fulfills an action.
  */
 class ExecutionResult<OutputT> internal constructor(
-    val startDictation: Boolean,
+    @get:JvmName("shouldStartDictation")
+    val shouldStartDictation: Boolean,
     val output: OutputT?,
 ) {
     override fun toString() =
-        "ExecutionResult(startDictation=$startDictation,output=$output)"
+        "ExecutionResult(shouldStartDictation=$shouldStartDictation,output=$output)"
 
     override fun equals(other: Any?): Boolean {
         return other is ExecutionResult<*> && output == other.output
     }
 
-    override fun hashCode() = Objects.hash(startDictation, output)
+    override fun hashCode() = Objects.hash(shouldStartDictation, output)
 
     /**
      * Builder for ExecutionResult.
      */
     class Builder<OutputT> {
-        private var startDictation: Boolean = false
-
+        private var shouldStartDictation: Boolean = false
         private var output: OutputT? = null
 
         /** Sets whether or not this fulfillment should start dictation. */
         fun setStartDictation(startDictation: Boolean) = apply {
-            this.startDictation = startDictation
+            this.shouldStartDictation = startDictation
         }
 
         /** Sets the execution output. */
@@ -52,12 +52,6 @@
         }
 
         /** Builds and returns the ExecutionResult instance. */
-        fun build() = ExecutionResult(startDictation, output)
-    }
-
-    companion object {
-        /** Returns a default ExecutionResult instance. */
-        @JvmStatic
-        fun <OutputT> getDefaultInstance() = ExecutionResult.Builder<OutputT>().build()
+        fun build() = ExecutionResult(shouldStartDictation, output)
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionFactory.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionSessionFactory.kt
similarity index 82%
rename from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionFactory.kt
rename to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionSessionFactory.kt
index 11c32cf..e3e2fb9 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionFactory.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ExecutionSessionFactory.kt
@@ -17,18 +17,18 @@
 package androidx.appactions.interaction.capabilities.core
 
 /**
- * Interface to be implemented for creating SessionT instances.
+ * Interface to be implemented for creating [ExecutionSessionT] instances.
  */
-fun interface SessionFactory<SessionT> {
+fun interface ExecutionSessionFactory<ExecutionSessionT> {
     /**
      * Implement this method to create session for handling assistant requests.
      *
      * @param hostProperties only applicable while used with AppInteractionService. Contains the
      *   dimensions of the UI area. Null when used without AppInteractionService.
      *
-     * @return A new SessionT instance for handling a task.
+     * @return A new ExecutionSessionT instance for handling a task.
      */
     fun createSession(
         hostProperties: HostProperties?,
-    ): SessionT
+    ): ExecutionSessionT
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
similarity index 80%
rename from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
rename to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
index f01729c..fd9cbca 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
@@ -17,13 +17,13 @@
 package androidx.appactions.interaction.capabilities.core
 
 /**
- * InitArg contains data passed to {@code BaseSession#onInit}.
+ * [SessionContext] contains data passed to [BaseExecutionSession.onCreate].
  */
-class InitArg internal constructor() {
+class SessionContext internal constructor() {
     override fun toString() =
-        "InitArg()"
+        "SessionContext()"
 
     override fun equals(other: Any?): Boolean {
-        return other is InitArg
+        return other is SessionContext
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityLookupResponse.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityLookupResponse.kt
index e271cc5..029e261 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityLookupResponse.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityLookupResponse.kt
@@ -51,7 +51,7 @@
         return result
     }
 
-    /** Builder class for [Entity]. */
+    /** Builder class for [EntityLookupResponse]. */
     class Builder<T> {
         private var candidateList: List<EntityLookupCandidate<T>> = listOf()
 
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
index 8275d0b..c3fcad0 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/entity/EntityProvider.kt
@@ -35,14 +35,18 @@
  *
  * <p>Use abstract classes within the library to create instances of the {@link EntityProvider}.
  */
-abstract class EntityProvider<T : Thing> internal constructor(private val typeSpec: TypeSpec<T>) {
+abstract class EntityProvider<T : Thing>
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+constructor(
+    private val typeSpec: TypeSpec<T>
+) {
     private val entityConverter = EntityConverter.of(typeSpec)
 
     /**
      * Unique identifier for this EntityFilter. Must match the shortcuts.xml declaration, which
      * allows different filters to be assigned to types on a per-BII basis.
      */
-    abstract fun getId(): String
+    abstract val id: String
 
     /**
      * Executes the entity lookup.
@@ -116,7 +120,7 @@
     }
 
     private fun convertStatus(
-        @EntityLookupResponse.EntityLookupStatus status: Int,
+        @EntityLookupResponse.EntityLookupStatus status: Int
     ): GroundingResponse.Status {
         return when (status) {
             EntityLookupResponse.CANCELED -> GroundingResponse.Status.CANCELED
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/CapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/CapabilitySession.kt
index 8875542..6d3b2de 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/CapabilitySession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/CapabilitySession.kt
@@ -37,7 +37,7 @@
      */
     fun execute(
         argumentsWrapper: ArgumentsWrapper,
-        callback: CallbackInternal,
+        callback: CallbackInternal
     )
 
     /**
@@ -61,7 +61,8 @@
     val status: Status
 
     /**
-     * The developer-provided external object (either a BaseSession instance or an ActionExecutor instance).
+     * The developer-provided external object (either a BaseExecutionSession instance or an
+     * ActionExecutor instance).
      */
     val uiHandle: Any
 
@@ -70,6 +71,6 @@
         UNINITIATED,
         IN_PROGRESS,
         COMPLETED,
-        DESTROYED,
+        DESTROYED
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
index 56fb833..826b7da 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityImpl.kt
@@ -17,8 +17,8 @@
 package androidx.appactions.interaction.capabilities.core.impl
 
 import androidx.annotation.RestrictTo
+import androidx.appactions.interaction.capabilities.core.ActionExecutor
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync
 import androidx.appactions.interaction.capabilities.core.HostProperties
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction
@@ -29,23 +29,21 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 internal class SingleTurnCapabilityImpl<
     PropertyT,
-    ArgumentT,
+    ArgumentsT,
     OutputT,
     > constructor(
-    override val id: String,
-    val actionSpec: ActionSpec<PropertyT, ArgumentT, OutputT>,
+    id: String,
+    val actionSpec: ActionSpec<PropertyT, ArgumentsT, OutputT>,
     val property: PropertyT,
-    val actionExecutorAsync: ActionExecutorAsync<ArgumentT, OutputT>,
-) : Capability {
-    override val supportsMultiTurnTask = false
-    val mutex = Mutex()
+    val actionExecutor: ActionExecutor<ArgumentsT, OutputT>,
+) : Capability(id) {
+    private val mutex = Mutex()
 
-    override fun getAppAction(): AppAction {
-        return actionSpec.convertPropertyToProto(property).toBuilder()
+    override val appAction: AppAction =
+        actionSpec.convertPropertyToProto(property).toBuilder()
             .setTaskInfo(TaskInfo.newBuilder().setSupportsPartialFulfillment(false))
             .setIdentifier(id)
             .build()
-    }
 
     override fun createSession(
         sessionId: String,
@@ -54,7 +52,7 @@
         return SingleTurnCapabilitySession(
             sessionId,
             actionSpec,
-            actionExecutorAsync,
+            actionExecutor,
             mutex,
         )
     }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
index 7a05e16..72c2c03 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
@@ -17,14 +17,14 @@
 package androidx.appactions.interaction.capabilities.core.impl
 
 import androidx.annotation.RestrictTo
-import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync
+import androidx.appactions.interaction.capabilities.core.ActionExecutor
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
 import androidx.appactions.interaction.proto.AppActionsContext.AppDialogState
 import androidx.appactions.interaction.proto.FulfillmentResponse
 import androidx.appactions.interaction.proto.ParamValue
-import androidx.concurrent.futures.await
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.sync.Mutex
@@ -36,12 +36,12 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 internal class SingleTurnCapabilitySession<
-    ArgumentT,
+    ArgumentsT,
     OutputT,
->(
+    >(
     override val sessionId: String,
-    private val actionSpec: ActionSpec<*, ArgumentT, OutputT>,
-    private val actionExecutorAsync: ActionExecutorAsync<ArgumentT, OutputT>,
+    private val actionSpec: ActionSpec<*, ArgumentsT, OutputT>,
+    private val actionExecutor: ActionExecutor<ArgumentsT, OutputT>,
     private val mutex: Mutex,
     private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 ) : CapabilitySession {
@@ -54,7 +54,7 @@
             throw UnsupportedOperationException()
         }
 
-    override val uiHandle: Any = actionExecutorAsync.uiHandle
+    override val uiHandle: Any = actionExecutor.uiHandle
 
     override fun destroy() {}
 
@@ -69,12 +69,12 @@
     ) {
         val paramValuesMap: Map<String, List<ParamValue>> =
             argumentsWrapper.paramValues.mapValues { entry -> entry.value.mapNotNull { it.value } }
-        val argument = actionSpec.buildArgument(paramValuesMap)
-        scope.launch {
+        val arguments = actionSpec.buildArguments(paramValuesMap)
+        scope.launch(start = CoroutineStart.UNDISPATCHED) {
             try {
                 mutex.lock(owner = this@SingleTurnCapabilitySession)
                 UiHandleRegistry.registerUiHandle(uiHandle, sessionId)
-                val output = actionExecutorAsync.execute(argument).await()
+                val output = actionExecutor.onExecute(arguments)
                 callback.onSuccess(convertToFulfillmentResponse(output))
             } catch (t: Throwable) {
                 callback.onError(ErrorStatusInternal.CANCELLED)
@@ -90,7 +90,7 @@
         executionResult: ExecutionResult<OutputT>,
     ): FulfillmentResponse {
         val fulfillmentResponseBuilder =
-            FulfillmentResponse.newBuilder().setStartDictation(executionResult.startDictation)
+            FulfillmentResponse.newBuilder().setStartDictation(executionResult.shouldStartDictation)
         executionResult.output?.let {
             fulfillmentResponseBuilder.setExecutionOutput(
                 actionSpec.convertOutputToProto(it),
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/ListenableFutureHelper.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/ListenableFutureHelper.kt
index 617e967..b640f22 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/ListenableFutureHelper.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/ListenableFutureHelper.kt
@@ -14,12 +14,10 @@
     tag: String,
     block: suspend CoroutineScope.() -> T,
 ): ListenableFuture<T> {
-    val scope = CoroutineScope(Dispatchers.Default)
     return CallbackToFutureAdapter.getFuture { completer ->
-        val job =
-            scope.launch {
+        val job = CoroutineScope(Dispatchers.Unconfined).launch {
                 try {
-                    completer.set(scope.block())
+                    completer.set(block())
                 } catch (t: Throwable) {
                     completer.setException(t)
                 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/FieldBinding.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/FieldBinding.java
index 04a8afd..2e2f22a 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/FieldBinding.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/FieldBinding.java
@@ -16,7 +16,6 @@
 
 package androidx.appactions.interaction.capabilities.core.impl.converters;
 
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
 import androidx.appactions.interaction.protobuf.Value;
 
 import com.google.auto.value.AutoValue;
@@ -25,9 +24,9 @@
 import java.util.function.Function;
 
 @AutoValue
-abstract class FieldBinding<T, BuilderT extends BuilderOf<T>> {
+abstract class FieldBinding<T, BuilderT> {
 
-    static <T, BuilderT extends BuilderOf<T>> FieldBinding<T, BuilderT> create(
+    static <T, BuilderT> FieldBinding<T, BuilderT> create(
             String name,
             Function<T, Optional<Value>> valueGetter,
             CheckedInterfaces.BiConsumer<BuilderT, Optional<Value>> valueSetter) {
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
index aae6a13..60082a6 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConverters.java
@@ -26,10 +26,6 @@
 import androidx.appactions.interaction.capabilities.core.values.ItemList;
 import androidx.appactions.interaction.capabilities.core.values.ListItem;
 import androidx.appactions.interaction.capabilities.core.values.Message;
-import androidx.appactions.interaction.capabilities.core.values.Order;
-import androidx.appactions.interaction.capabilities.core.values.OrderItem;
-import androidx.appactions.interaction.capabilities.core.values.Organization;
-import androidx.appactions.interaction.capabilities.core.values.ParcelDelivery;
 import androidx.appactions.interaction.capabilities.core.values.Person;
 import androidx.appactions.interaction.capabilities.core.values.SafetyCheck;
 import androidx.appactions.interaction.capabilities.core.values.SearchAction;
@@ -60,62 +56,6 @@
                             ItemList.Builder::addAllListItems,
                             LIST_ITEM_TYPE_SPEC)
                     .build();
-    public static final TypeSpec<OrderItem> ORDER_ITEM_TYPE_SPEC =
-            TypeSpecBuilder.newBuilderForThing("OrderItem", OrderItem::newBuilder).build();
-    public static final TypeSpec<Organization> ORGANIZATION_TYPE_SPEC =
-            TypeSpecBuilder.newBuilderForThing("Organization", Organization::newBuilder).build();
-    public static final TypeSpec<ParcelDelivery> PARCEL_DELIVERY_TYPE_SPEC =
-            TypeSpecBuilder.newBuilder("ParcelDelivery", ParcelDelivery::newBuilder)
-                    .bindStringField(
-                            "deliveryAddress",
-                            ParcelDelivery::getDeliveryAddress,
-                            ParcelDelivery.Builder::setDeliveryAddress)
-                    .bindZonedDateTimeField(
-                            "expectedArrivalFrom",
-                            ParcelDelivery::getExpectedArrivalFrom,
-                            ParcelDelivery.Builder::setExpectedArrivalFrom)
-                    .bindZonedDateTimeField(
-                            "expectedArrivalUntil",
-                            ParcelDelivery::getExpectedArrivalUntil,
-                            ParcelDelivery.Builder::setExpectedArrivalUntil)
-                    .bindStringField(
-                            "hasDeliveryMethod",
-                            ParcelDelivery::getDeliveryMethod,
-                            ParcelDelivery.Builder::setDeliveryMethod)
-                    .bindStringField(
-                            "trackingNumber",
-                            ParcelDelivery::getTrackingNumber,
-                            ParcelDelivery.Builder::setTrackingNumber)
-                    .bindStringField(
-                            "trackingUrl",
-                            ParcelDelivery::getTrackingUrl,
-                            ParcelDelivery.Builder::setTrackingUrl)
-                    .build();
-    public static final TypeSpec<Order> ORDER_TYPE_SPEC =
-            TypeSpecBuilder.newBuilderForThing("Order", Order::newBuilder)
-                    .bindZonedDateTimeField(
-                            "orderDate", Order::getOrderDate, Order.Builder::setOrderDate)
-                    .bindSpecField(
-                            "orderDelivery",
-                            Order::getOrderDelivery,
-                            Order.Builder::setOrderDelivery,
-                            PARCEL_DELIVERY_TYPE_SPEC)
-                    .bindRepeatedSpecField(
-                            "orderedItem",
-                            Order::getOrderedItems,
-                            Order.Builder::addAllOrderedItems,
-                            ORDER_ITEM_TYPE_SPEC)
-                    .bindEnumField(
-                            "orderStatus",
-                            Order::getOrderStatus,
-                            Order.Builder::setOrderStatus,
-                            Order.OrderStatus.class)
-                    .bindSpecField(
-                            "seller",
-                            Order::getSeller,
-                            Order.Builder::setSeller,
-                            ORGANIZATION_TYPE_SPEC)
-                    .build();
     public static final TypeSpec<Person> PERSON_TYPE_SPEC =
             TypeSpecBuilder.newBuilderForThing("Person", Person::newBuilder)
                     .bindStringField("email", Person::getEmail, Person.Builder::setEmail)
@@ -131,7 +71,7 @@
             new UnionTypeSpec.Builder<Attendee>()
                     .bindMemberType(
                             (attendee) -> attendee.asPerson().orElse(null),
-                            (person) -> new Attendee(person),
+                            Attendee::new,
                             PERSON_TYPE_SPEC)
                     .build();
     public static final TypeSpec<CalendarEvent> CALENDAR_EVENT_TYPE_SPEC =
@@ -161,14 +101,14 @@
             new UnionTypeSpec.Builder<Recipient>()
                     .bindMemberType(
                             (recipient) -> recipient.asPerson().orElse(null),
-                            (person) -> new Recipient(person),
+                            Recipient::new,
                             PERSON_TYPE_SPEC)
                     .build();
     public static final TypeSpec<Participant> PARTICIPANT_TYPE_SPEC =
             new UnionTypeSpec.Builder<Participant>()
                     .bindMemberType(
                             (participant) -> participant.asPerson().orElse(null),
-                            (person) -> new Participant(person),
+                            Participant::new,
                             PERSON_TYPE_SPEC)
                     .build();
     public static final TypeSpec<Message> MESSAGE_TYPE_SPEC =
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
index e07ebe3..995efc3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecBuilder.java
@@ -38,14 +38,31 @@
 import java.util.function.Supplier;
 
 /** Builder for {@link TypeSpec}. */
-final class TypeSpecBuilder<T, BuilderT extends BuilderOf<T>> {
+final class TypeSpecBuilder<T, BuilderT> {
     private final List<FieldBinding<T, BuilderT>> mBindings = new ArrayList<>();
     private final Supplier<BuilderT> mBuilderSupplier;
+    private final Function<BuilderT, T> mBuilderFinalizer;
     private CheckedInterfaces.Consumer<Struct> mStructValidator;
     private Function<T, Optional<String>> mIdentifierGetter = (unused) -> Optional.empty();
 
-    private TypeSpecBuilder(Supplier<BuilderT> builderSupplier) {
+    private TypeSpecBuilder(
+            String typeName,
+            Supplier<BuilderT> builderSupplier,
+            Function<BuilderT, T> builderFinalizer) {
         this.mBuilderSupplier = builderSupplier;
+        this.mBuilderFinalizer = builderFinalizer;
+        this.bindStringField("@type", (unused) -> Optional.of(typeName), (builder, val) -> {})
+                .setStructValidator(
+                        struct -> {
+                            if (!getFieldFromStruct(struct, "@type")
+                                    .getStringValue()
+                                    .equals(typeName)) {
+                                throw new StructConversionException(
+                                        String.format(
+                                                "Struct @type field must be equal to %s.",
+                                                typeName));
+                            }
+                        });
     }
 
     private static Value getStringValue(String string) {
@@ -77,19 +94,7 @@
 
     static <T, BuilderT extends BuilderOf<T>> TypeSpecBuilder<T, BuilderT> newBuilder(
             String typeName, Supplier<BuilderT> builderSupplier) {
-        return new TypeSpecBuilder<>(builderSupplier)
-                .bindStringField("@type", (unused) -> Optional.of(typeName), (builder, val) -> {})
-                .setStructValidator(
-                        struct -> {
-                            if (!getFieldFromStruct(struct, "@type")
-                                    .getStringValue()
-                                    .equals(typeName)) {
-                                throw new StructConversionException(
-                                        String.format(
-                                                "Struct @type field must be equal to %s.",
-                                                typeName));
-                            }
-                        });
+        return new TypeSpecBuilder<>(typeName, builderSupplier, BuilderT::build);
     }
 
     /**
@@ -106,6 +111,31 @@
                 .bindStringField("name", T::getName, BuilderT::setName);
     }
 
+    /**
+     * Creates a new TypeSpecBuilder for a child class of Thing (temporary BuiltInTypes).
+     *
+     * <p>Comes with bindings for Thing fields.
+     */
+    static <T extends androidx.appactions.builtintypes.types.Thing,
+            BuilderT extends androidx.appactions.builtintypes.types.Thing.Builder<?>>
+            TypeSpecBuilder<T, BuilderT> newBuilderForThing(
+                    String typeName,
+                    Supplier<BuilderT> builderSupplier,
+                    Function<BuilderT, T> builderFinalizer) {
+        return new TypeSpecBuilder<>(typeName, builderSupplier, builderFinalizer)
+                .bindIdentifier(thing -> Optional.ofNullable(thing.getIdentifier()))
+                .bindStringField(
+                        "identifier",
+                        thing -> Optional.ofNullable(thing.getIdentifier()),
+                        BuilderT::setIdentifier)
+                .bindStringField(
+                        "name",
+                        thing ->
+                                Optional.ofNullable(thing.getName())
+                                        .flatMap(name -> Optional.ofNullable(name.asText())),
+                        BuilderT::setName);
+    }
+
     private TypeSpecBuilder<T, BuilderT> setStructValidator(
             CheckedInterfaces.Consumer<Struct> structValidator) {
         this.mStructValidator = structValidator;
@@ -308,6 +338,7 @@
                 mIdentifierGetter,
                 mBindings,
                 mBuilderSupplier,
+                mBuilderFinalizer,
                 Optional.ofNullable(mStructValidator));
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImpl.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImpl.java
index ab39a4fb..48f5a0c 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImpl.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImpl.java
@@ -18,7 +18,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
 import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
 import androidx.appactions.interaction.protobuf.Struct;
 import androidx.appactions.interaction.protobuf.Value;
@@ -34,7 +33,7 @@
  * TypeSpecImpl is used to convert between java/kotlin objects in capabilities/values and Value
  * proto.
  */
-final class TypeSpecImpl<T, BuilderT extends BuilderOf<T>> implements TypeSpec<T> {
+final class TypeSpecImpl<T, BuilderT> implements TypeSpec<T> {
     /* The function to retrieve the identifier. */
     final Function<T, Optional<String>> mIdentifierGetter;
 
@@ -47,15 +46,20 @@
     /** Supplies BuilderT instances. */
     final Supplier<BuilderT> mBuilderSupplier;
 
+    /** Builds the object instance. */
+    final Function<BuilderT, T> mBuilderFinalizer;
+
     TypeSpecImpl(
             Function<T, Optional<String>> identifierGetter,
             List<FieldBinding<T, BuilderT>> bindings,
             Supplier<BuilderT> builderSupplier,
+            Function<BuilderT, T> builderFinalizer,
             Optional<CheckedInterfaces.Consumer<Struct>> structValidator) {
         this.mIdentifierGetter = identifierGetter;
         this.mBindings = Collections.unmodifiableList(bindings);
         this.mBuilderSupplier = builderSupplier;
         this.mStructValidator = structValidator;
+        this.mBuilderFinalizer = builderFinalizer;
     }
 
     @Nullable
@@ -100,6 +104,6 @@
             Optional<Value> fieldValue = Optional.ofNullable(fieldsMap.get(binding.name()));
             binding.valueSetter().accept(builder, fieldValue);
         }
-        return builder.build();
+        return mBuilderFinalizer.apply(builder);
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.java
index 182cef8..e17f14c 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpec.java
@@ -29,10 +29,10 @@
  * A specification for an action, describing it from the app's point of view.
  *
  * @param <PropertyT> typed description of action's characteristics.
- * @param <ArgumentT> typed representation of action's arguments.
+ * @param <ArgumentsT> typed representation of action's arguments.
  * @param <OutputT>   typed action's execution output.
  */
-public interface ActionSpec<PropertyT, ArgumentT, OutputT> {
+public interface ActionSpec<PropertyT, ArgumentsT, OutputT> {
 
     /** Converts the property to the {@code AppAction} proto. */
     @NonNull
@@ -40,7 +40,7 @@
 
     /** Builds this action's arguments from an ArgumentsWrapper instance. */
     @NonNull
-    ArgumentT buildArgument(@NonNull Map<String, List<ParamValue>> args)
+    ArgumentsT buildArguments(@NonNull Map<String, List<ParamValue>> args)
             throws StructConversionException;
 
     /** Converts the output to the {@code StructuredOutput} proto. */
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.java
index be9eed1..e95f904 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecBuilder.java
@@ -24,7 +24,7 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter;
 import androidx.appactions.interaction.capabilities.core.impl.converters.SlotTypeConverter;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ParamBinding.ArgumentSetter;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.proto.AppActionsContext.IntentParameter;
 import androidx.appactions.interaction.proto.ParamValue;
 
@@ -42,28 +42,28 @@
  * A builder for the {@code ActionSpec}.
  *
  * @param <PropertyT>
- * @param <ArgumentT>
- * @param <ArgumentBuilderT>
+ * @param <ArgumentsT>
+ * @param <ArgumentsBuilderT>
  * @param <OutputT>
  */
 public final class ActionSpecBuilder<
-        PropertyT, ArgumentT, ArgumentBuilderT extends BuilderOf<ArgumentT>, OutputT> {
+        PropertyT, ArgumentsT, ArgumentsBuilderT extends BuilderOf<ArgumentsT>, OutputT> {
 
     private final String mCapabilityName;
-    private final Supplier<ArgumentBuilderT> mArgumentBuilderSupplier;
-    private final ArrayList<ParamBinding<PropertyT, ArgumentT, ArgumentBuilderT>>
+    private final Supplier<ArgumentsBuilderT> mArgumentBuilderSupplier;
+    private final ArrayList<ParamBinding<PropertyT, ArgumentsT, ArgumentsBuilderT>>
             mParamBindingList = new ArrayList<>();
     private final Map<String, Function<OutputT, List<ParamValue>>> mOutputBindings =
             new HashMap<>();
 
     private ActionSpecBuilder(
-            String capabilityName, Supplier<ArgumentBuilderT> argumentBuilderSupplier) {
+            String capabilityName, Supplier<ArgumentsBuilderT> argumentBuilderSupplier) {
         this.mCapabilityName = capabilityName;
         this.mArgumentBuilderSupplier = argumentBuilderSupplier;
     }
 
     /**
-     * Creates an empty {@code ActionSpecBuilder} with the given capability name. ArgumentT is set
+     * Creates an empty {@code ActionSpecBuilder} with the given capability name. ArgumentsT is set
      * to Object as a placeholder, which must be replaced by calling setArgument.
      */
     @NonNull
@@ -75,23 +75,23 @@
     /** Sets the property type and returns a new {@code ActionSpecBuilder}. */
     @NonNull
     public <NewPropertyT>
-            ActionSpecBuilder<NewPropertyT, ArgumentT, ArgumentBuilderT, OutputT> setDescriptor(
+            ActionSpecBuilder<NewPropertyT, ArgumentsT, ArgumentsBuilderT, OutputT> setDescriptor(
                     @NonNull Class<NewPropertyT> unused) {
         return new ActionSpecBuilder<>(this.mCapabilityName, this.mArgumentBuilderSupplier);
     }
 
     /** Sets the argument type and its builder and returns a new {@code ActionSpecBuilder}. */
     @NonNull
-    public <NewArgumentT, NewArgumentBuilderT extends BuilderOf<NewArgumentT>>
-            ActionSpecBuilder<PropertyT, NewArgumentT, NewArgumentBuilderT, OutputT> setArgument(
-                    @NonNull Class<NewArgumentT> unused,
-                    @NonNull Supplier<NewArgumentBuilderT> argumentBuilderSupplier) {
+    public <NewArgumentsT, NewArgumentsBuilderT extends BuilderOf<NewArgumentsT>>
+            ActionSpecBuilder<PropertyT, NewArgumentsT, NewArgumentsBuilderT, OutputT> setArguments(
+                    @NonNull Class<NewArgumentsT> unused,
+                    @NonNull Supplier<NewArgumentsBuilderT> argumentBuilderSupplier) {
         return new ActionSpecBuilder<>(this.mCapabilityName, argumentBuilderSupplier);
     }
 
     @NonNull
     public <NewOutputT>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, NewOutputT> setOutput(
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, NewOutputT> setOutput(
                     @NonNull Class<NewOutputT> unused) {
         return new ActionSpecBuilder<>(this.mCapabilityName, this.mArgumentBuilderSupplier);
     }
@@ -105,23 +105,23 @@
      * @return the builder itself.
      */
     @NonNull
-    private ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT>
+    private ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT>
             bindParameterInternal(
                     @NonNull String paramName,
                     @NonNull Function<? super PropertyT, Optional<IntentParameter>> paramGetter,
-                    @NonNull ArgumentSetter<ArgumentBuilderT> argumentSetter) {
+                    @NonNull ArgumentSetter<ArgumentsBuilderT> argumentSetter) {
         mParamBindingList.add(ParamBinding.create(paramName, paramGetter, argumentSetter));
         return this;
     }
 
     /**
-     * Binds the parameter name, getter, and setter for a {@link TypeProperty}.
+     * Binds the parameter name, getter, and setter for a {@link Property}.
      *
      * <p>This parameter is required for any capability built from the generated {@link ActionSpec}.
      *
      * @param paramName the name of this action' parameter.
-     * @param propertyGetter a getter of the TypeProperty from the property, which must be able to
-     *     fetch a non-null {@code TypeProperty} from {@code PropertyT}.
+     * @param propertyGetter a getter of the Property from the property, which must be able to
+     *     fetch a non-null {@code Property} from {@code PropertyT}.
      * @param paramConsumer a setter to set the string value in the argument builder.
      * @param paramValueConverter converter FROM assistant ParamValue proto
      * @param entityConverter converter TO assistant Entity proto
@@ -129,12 +129,12 @@
      */
     @NonNull
     public <T, PossibleValueT>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT> bindParameter(
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT> bindParameter(
                     @NonNull String paramName,
                     @NonNull
-                            Function<? super PropertyT, TypeProperty<PossibleValueT>>
+                            Function<? super PropertyT, Property<PossibleValueT>>
                                     propertyGetter,
-                    @NonNull BiConsumer<? super ArgumentBuilderT, T> paramConsumer,
+                    @NonNull BiConsumer<? super ArgumentsBuilderT, T> paramConsumer,
                     @NonNull ParamValueConverter<T> paramValueConverter,
                     @NonNull EntityConverter<PossibleValueT> entityConverter) {
         return bindOptionalParameter(
@@ -146,16 +146,16 @@
     }
 
     /**
-     * Binds the parameter name, getter, and setter for a {@link TypeProperty}.
+     * Binds the parameter name, getter, and setter for a {@link Property}.
      *
      * <p>This parameter is optional for any capability built from the generated {@link ActionSpec}.
      * If the Property Optional is not set, this parameter will not exist in the parameter
      * definition of the capability.
      *
      * @param paramName the name of this action' parameter.
-     * @param optionalPropertyGetter an optional getter of the TypeProperty from the property, which
-     *     may be able to fetch a non-null {@code TypeProperty} from {@code PropertyT}, or get
-     *     {@link Optional#empty}.
+     * @param optionalPropertyGetter an optional getter of the Property from the property,
+     *     which may be able to fetch a non-null {@code Property} from {@code PropertyT},
+     *     or get {@link Optional#empty}.
      * @param paramConsumer a setter to set the string value in the argument builder.
      * @param paramValueConverter converter FROM assistant ParamValue proto
      * @param entityConverter converter TO assistant Entity proto
@@ -163,15 +163,15 @@
      */
     @NonNull
     public <T, PossibleValueT>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT>
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT>
                     bindOptionalParameter(
                             @NonNull String paramName,
                             @NonNull
                                     Function<
                                                     ? super PropertyT,
-                                                    Optional<TypeProperty<PossibleValueT>>>
+                                                    Optional<Property<PossibleValueT>>>
                                             optionalPropertyGetter,
-                            @NonNull BiConsumer<? super ArgumentBuilderT, T> paramConsumer,
+                            @NonNull BiConsumer<? super ArgumentsBuilderT, T> paramConsumer,
                             @NonNull ParamValueConverter<T> paramValueConverter,
                             @NonNull EntityConverter<PossibleValueT> entityConverter) {
         return bindParameterInternal(
@@ -200,15 +200,15 @@
      */
     @NonNull
     public <T, PossibleValueT>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT>
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT>
                     bindRepeatedParameter(
                             @NonNull String paramName,
                             @NonNull
                                     Function<
                                                     ? super PropertyT,
-                                                    Optional<TypeProperty<PossibleValueT>>>
+                                                    Optional<Property<PossibleValueT>>>
                                             optionalPropertyGetter,
-                            @NonNull BiConsumer<? super ArgumentBuilderT, List<T>> paramConsumer,
+                            @NonNull BiConsumer<? super ArgumentsBuilderT, List<T>> paramConsumer,
                             @NonNull ParamValueConverter<T> paramValueConverter,
                             @NonNull EntityConverter<PossibleValueT> entityConverter) {
         return bindParameterInternal(
@@ -234,7 +234,7 @@
     @NonNull
     @SuppressWarnings("JdkCollectors")
     public <T>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT> bindOptionalOutput(
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT> bindOptionalOutput(
                     @NonNull String name,
                     @NonNull Function<OutputT, Optional<T>> outputGetter,
                     @NonNull Function<T, ParamValue> converter) {
@@ -261,7 +261,7 @@
     @NonNull
     @SuppressWarnings("JdkCollectors")
     public <T>
-            ActionSpecBuilder<PropertyT, ArgumentT, ArgumentBuilderT, OutputT> bindRepeatedOutput(
+            ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT> bindRepeatedOutput(
                     @NonNull String name,
                     @NonNull Function<OutputT, List<T>> outputGetter,
                     @NonNull Function<T, ParamValue> converter) {
@@ -276,7 +276,7 @@
 
     /** Builds an {@code ActionSpec} from this builder. */
     @NonNull
-    public ActionSpec<PropertyT, ArgumentT, OutputT> build() {
+    public ActionSpec<PropertyT, ArgumentsT, OutputT> build() {
         return new ActionSpecImpl<>(
                 mCapabilityName,
                 mArgumentBuilderSupplier,
@@ -284,11 +284,11 @@
                 mOutputBindings);
     }
 
-    /** Create IntentParameter proto from a TypeProperty. */
+    /** Create IntentParameter proto from a Property. */
     @NonNull
     private static <T> IntentParameter buildIntentParameter(
             @NonNull String paramName,
-            @NonNull TypeProperty<T> property,
+            @NonNull Property<T> property,
             @NonNull EntityConverter<T> entityConverter) {
         IntentParameter.Builder builder = IntentParameter.newBuilder()
                 .setName(paramName)
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.java
index 906e2b6..47f0a1a 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecImpl.java
@@ -33,18 +33,18 @@
 
 /** The implementation of {@code ActionSpec} interface. */
 final class ActionSpecImpl<
-                PropertyT, ArgumentT, ArgumentBuilderT extends BuilderOf<ArgumentT>, OutputT>
-        implements ActionSpec<PropertyT, ArgumentT, OutputT> {
+                PropertyT, ArgumentsT, ArgumentsBuilderT extends BuilderOf<ArgumentsT>, OutputT>
+        implements ActionSpec<PropertyT, ArgumentsT, OutputT> {
 
     private final String mCapabilityName;
-    private final Supplier<ArgumentBuilderT> mArgumentBuilderSupplier;
-    private final List<ParamBinding<PropertyT, ArgumentT, ArgumentBuilderT>> mParamBindingList;
+    private final Supplier<ArgumentsBuilderT> mArgumentBuilderSupplier;
+    private final List<ParamBinding<PropertyT, ArgumentsT, ArgumentsBuilderT>> mParamBindingList;
     private final Map<String, Function<OutputT, List<ParamValue>>> mOutputBindings;
 
     ActionSpecImpl(
             String capabilityName,
-            Supplier<ArgumentBuilderT> argumentBuilderSupplier,
-            List<ParamBinding<PropertyT, ArgumentT, ArgumentBuilderT>> paramBindingList,
+            Supplier<ArgumentsBuilderT> argumentBuilderSupplier,
+            List<ParamBinding<PropertyT, ArgumentsT, ArgumentsBuilderT>> paramBindingList,
             Map<String, Function<OutputT, List<ParamValue>>> outputBindings) {
         this.mCapabilityName = capabilityName;
         this.mArgumentBuilderSupplier = argumentBuilderSupplier;
@@ -68,16 +68,16 @@
 
     @NonNull
     @Override
-    public ArgumentT buildArgument(Map<String, List<ParamValue>> args)
+    public ArgumentsT buildArguments(@NonNull Map<String, List<ParamValue>> args)
             throws StructConversionException {
-        ArgumentBuilderT argumentBuilder = mArgumentBuilderSupplier.get();
-        for (ParamBinding<PropertyT, ArgumentT, ArgumentBuilderT> binding : mParamBindingList) {
+        ArgumentsBuilderT argumentBuilder = mArgumentBuilderSupplier.get();
+        for (ParamBinding<PropertyT, ArgumentsT, ArgumentsBuilderT> binding : mParamBindingList) {
             List<ParamValue> paramValues = args.get(binding.name());
             if (paramValues == null) {
                 continue;
             }
             try {
-                binding.argumentSetter().setArgument(argumentBuilder, paramValues);
+                binding.argumentSetter().setArguments(argumentBuilder, paramValues);
             } catch (StructConversionException e) {
                 // Wrap the exception with a more meaningful error message.
                 throw new StructConversionException(
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.java
index bdd5e08..f21f6f2 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ParamBinding.java
@@ -32,18 +32,18 @@
  * A binding between a parameter and its Property converter / Argument setter.
  *
  * @param <PropertyT>
- * @param <ArgumentT>
- * @param <ArgumentBuilderT>
+ * @param <ArgumentsT>
+ * @param <ArgumentsBuilderT>
  */
 @AutoValue
 public abstract class ParamBinding<
-        PropertyT, ArgumentT, ArgumentBuilderT extends BuilderOf<ArgumentT>> {
+        PropertyT, ArgumentsT, ArgumentsBuilderT extends BuilderOf<ArgumentsT>> {
 
-    static <PropertyT, ArgumentT, ArgumentBuilderT extends BuilderOf<ArgumentT>>
-            ParamBinding<PropertyT, ArgumentT, ArgumentBuilderT> create(
+    static <PropertyT, ArgumentsT, ArgumentsBuilderT extends BuilderOf<ArgumentsT>>
+            ParamBinding<PropertyT, ArgumentsT, ArgumentsBuilderT> create(
                     String name,
                     Function<? super PropertyT, Optional<IntentParameter>> paramGetter,
-                    ArgumentSetter<ArgumentBuilderT> argumentSetter) {
+                    ArgumentSetter<ArgumentsBuilderT> argumentSetter) {
         return new AutoValue_ParamBinding<>(name, paramGetter, argumentSetter);
     }
 
@@ -59,21 +59,23 @@
     public abstract Function<? super PropertyT, Optional<IntentParameter>> paramGetter();
 
     /**
-     * Populates the {@code ArgumentBuilderT} for this param with the {@code ParamValue} sent from
+     * Populates the {@code ArgumentsBuilderT} for this param with the {@code ParamValue} sent from
      * Assistant in Fulfillment.
      */
     @NonNull
-    public abstract ArgumentSetter<ArgumentBuilderT> argumentSetter();
+    public abstract ArgumentSetter<ArgumentsBuilderT> argumentSetter();
 
     /**
-     * Givne a {@code List<ParamValue>}, convert it to user-visible type and set it into
+     * Given a {@code List<ParamValue>}, convert it to user-visible type and set it into
      * ArgumentBuilder.
      *
-     * @param <ArgumentBuilderT>
+     * @param <ArgumentsBuilderT>
      */
     @FunctionalInterface
-    public interface ArgumentSetter<ArgumentBuilderT> {
-        void setArgument(@NonNull ArgumentBuilderT builder, @NonNull List<ParamValue> paramValues)
+    public interface ArgumentSetter<ArgumentsBuilderT> {
+
+        /** Conversion from protos to user-visible type. */
+        void setArguments(@NonNull ArgumentsBuilderT builder, @NonNull List<ParamValue> paramValues)
                 throws StructConversionException;
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/SessionBridge.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/SessionBridge.kt
index 8c78335..6242b6f8 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/SessionBridge.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/SessionBridge.kt
@@ -25,8 +25,8 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 fun interface SessionBridge<
-    SessionT,
+    ExecutionSessionT,
     ConfirmationT
 > {
-    fun createTaskHandler(externalSession: SessionT): TaskHandler<ConfirmationT>
+    fun createTaskHandler(externalSession: ExecutionSessionT): TaskHandler<ConfirmationT>
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
index edb51ab..fade42a 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilityImpl.kt
@@ -15,10 +15,11 @@
  */
 
 package androidx.appactions.interaction.capabilities.core.impl.task
+
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
 import androidx.appactions.interaction.capabilities.core.HostProperties
-import androidx.appactions.interaction.capabilities.core.SessionFactory
+import androidx.appactions.interaction.capabilities.core.ExecutionSessionFactory
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction
@@ -27,50 +28,51 @@
 
 /**
  * @param id a unique id for this capability, can be null
- * @param supportsMultiTurnTask whether this is a single-turn capability or a multi-turn capability
  * @param actionSpec the ActionSpec for this capability
- * @param sessionFactory the SessionFactory provided by the library user
- * @param sessionBridge a SessionBridge object that converts SessionT into TaskHandler instance
+ * @param sessionFactory the ExecutionSessionFactory provided by the library user
+ * @param sessionBridge a SessionBridge object that converts ExecutionSessionT into TaskHandler
+ *           instance
  * @param sessionUpdaterSupplier a Supplier of SessionUpdaterT instances
  */
 internal class TaskCapabilityImpl<
     PropertyT,
-    ArgumentT,
+    ArgumentsT,
     OutputT,
-    SessionT : BaseSession<ArgumentT, OutputT>,
+    ExecutionSessionT : BaseExecutionSession<ArgumentsT, OutputT>,
     ConfirmationT,
-    SessionUpdaterT,
-    > constructor(
-    override val id: String,
-    val actionSpec: ActionSpec<PropertyT, ArgumentT, OutputT>,
-    val property: PropertyT,
-    val sessionFactory: SessionFactory<SessionT>,
-    val sessionBridge: SessionBridge<SessionT, ConfirmationT>,
-    val sessionUpdaterSupplier: Supplier<SessionUpdaterT>,
-) : Capability {
+    SessionUpdaterT
+    >
+constructor(
+    id: String,
+    private val actionSpec: ActionSpec<PropertyT, ArgumentsT, OutputT>,
+    private val property: PropertyT,
+    private val sessionFactory: ExecutionSessionFactory<ExecutionSessionT>,
+    private val sessionBridge: SessionBridge<ExecutionSessionT, ConfirmationT>,
+    private val sessionUpdaterSupplier: Supplier<SessionUpdaterT>
+) : Capability(id) {
 
-    override val supportsMultiTurnTask = true
-
-    override fun getAppAction(): AppAction {
-        return actionSpec.convertPropertyToProto(property).toBuilder()
+    override val appAction: AppAction =
+        actionSpec
+            .convertPropertyToProto(property)
+            .toBuilder()
             .setTaskInfo(TaskInfo.newBuilder().setSupportsPartialFulfillment(true))
             .setIdentifier(id)
             .build()
-    }
 
     override fun createSession(
         sessionId: String,
-        hostProperties: HostProperties,
+        hostProperties: HostProperties
     ): CapabilitySession {
-        val externalSession = sessionFactory.createSession(
-            hostProperties,
-        )
+        val externalSession =
+            sessionFactory.createSession(
+                hostProperties
+            )
         return TaskCapabilitySession(
             sessionId,
             actionSpec,
-            getAppAction(),
+            appAction,
             sessionBridge.createTaskHandler(externalSession),
-            externalSession,
+            externalSession
         )
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
index 27f57a1..c4a4b39 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskCapabilitySession.kt
@@ -17,7 +17,7 @@
 package androidx.appactions.interaction.capabilities.core.impl.task
 
 import androidx.annotation.GuardedBy
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
 import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal
@@ -28,19 +28,20 @@
 import androidx.appactions.interaction.proto.AppActionsContext.AppDialogState
 import androidx.appactions.interaction.proto.ParamValue
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 
 internal class TaskCapabilitySession<
-    ArgumentT,
+    ArgumentsT,
     OutputT,
     ConfirmationT,
 >(
     override val sessionId: String,
-    actionSpec: ActionSpec<*, ArgumentT, OutputT>,
+    actionSpec: ActionSpec<*, ArgumentsT, OutputT>,
     appAction: AppAction,
     taskHandler: TaskHandler<ConfirmationT>,
-    externalSession: BaseSession<ArgumentT, OutputT>,
+    externalSession: BaseExecutionSession<ArgumentsT, OutputT>,
     private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 ) : CapabilitySession, TaskUpdateHandler {
     override val state: AppDialogState
@@ -63,7 +64,7 @@
     /** Contains session state and request processing logic. */
     private val sessionOrchestrator:
         TaskOrchestrator<
-            ArgumentT,
+            ArgumentsT,
             OutputT,
             ConfirmationT,
         > =
@@ -135,7 +136,7 @@
                 pendingTouchEventRequest = null
             }
             if (nextRequest != null) {
-                scope.launch {
+                scope.launch(start = CoroutineStart.UNDISPATCHED) {
                     sessionOrchestrator.processUpdateRequest(nextRequest)
                     dispatchPendingRequestIfIdle()
                 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
index 1e2345e..30bc097 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/TaskOrchestrator.kt
@@ -16,10 +16,10 @@
 package androidx.appactions.interaction.capabilities.core.impl.task
 
 import androidx.annotation.GuardedBy
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.ConfirmationOutput
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
-import androidx.appactions.interaction.capabilities.core.InitArg
+import androidx.appactions.interaction.capabilities.core.SessionContext
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
 import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper
 import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
@@ -54,12 +54,12 @@
  *
  * Only one request can be processed at a time.
  */
-internal class TaskOrchestrator<ArgumentT, OutputT, ConfirmationT>(
+internal class TaskOrchestrator<ArgumentsT, OutputT, ConfirmationT>(
     private val sessionId: String,
-    private val actionSpec: ActionSpec<*, ArgumentT, OutputT>,
+    private val actionSpec: ActionSpec<*, ArgumentsT, OutputT>,
     private val appAction: AppActionsContext.AppAction,
     private val taskHandler: TaskHandler<ConfirmationT>,
-    private val externalSession: BaseSession<ArgumentT, OutputT>,
+    private val externalSession: BaseExecutionSession<ArgumentsT, OutputT>,
 ) {
     /**
      * A [reader-writer lock](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) to protect
@@ -216,7 +216,7 @@
                     )
                 processFulfillmentValues(fulfillmentValuesMap)
             }
-            val fulfillmentResponse = maybeConfirmOrFinish()
+            val fulfillmentResponse = maybeConfirmOrExecute()
             LoggerInternal.log(CapabilityLogger.LogLevel.INFO, LOG_TAG, "Manual input success")
             if (mTouchEventCallback != null) {
                 mTouchEventCallback!!.onSuccess(
@@ -256,7 +256,7 @@
      * Otherwise, the future contains a FulfillmentResponse containing BIC or BIO data.
      */
     @Throws(StructConversionException::class, MissingRequiredArgException::class)
-    private suspend fun maybeConfirmOrFinish(): FulfillmentResponse {
+    private suspend fun maybeConfirmOrExecute(): FulfillmentResponse {
         val finalArguments = getCurrentAcceptedArguments()
         if (
             anyParamsOfStatus(CurrentValue.Status.REJECTED) ||
@@ -273,7 +273,7 @@
 
     private fun maybeInitializeTask() {
         if (status === CapabilitySession.Status.UNINITIATED) {
-            externalSession.onInit(InitArg())
+            externalSession.onCreate(SessionContext())
         }
         status = CapabilitySession.Status.IN_PROGRESS
     }
@@ -289,7 +289,7 @@
         clearMissingArgs(argumentsWrapper)
         return try {
             processFulfillmentValues(argumentsWrapper.paramValues)
-            val fulfillmentResponse = maybeConfirmOrFinish()
+            val fulfillmentResponse = maybeConfirmOrExecute()
             LoggerInternal.log(CapabilityLogger.LogLevel.INFO, LOG_TAG, "Task sync success")
             FulfillmentResult(fulfillmentResponse)
         } catch (t: Throwable) {
@@ -449,9 +449,10 @@
     private suspend fun getFulfillmentResponseForExecution(
         finalArguments: Map<String, List<ParamValue>>,
     ): FulfillmentResponse {
-        val result = externalSession.onFinish(actionSpec.buildArgument(finalArguments))
+        val result = externalSession.onExecute(actionSpec.buildArguments(finalArguments))
         status = CapabilitySession.Status.COMPLETED
-        val fulfillmentResponse = FulfillmentResponse.newBuilder()
+        val fulfillmentResponse =
+            FulfillmentResponse.newBuilder().setStartDictation(result.shouldStartDictation)
         convertToExecutionOutput(result)?.let { fulfillmentResponse.executionOutput = it }
         return fulfillmentResponse.build()
     }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/exceptions/MissingRequiredArgException.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/exceptions/MissingRequiredArgException.java
index f3240cf..32b3fda 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/exceptions/MissingRequiredArgException.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/task/exceptions/MissingRequiredArgException.java
@@ -19,7 +19,7 @@
 import androidx.annotation.NonNull;
 
 /**
- * During the onFinishListener handling, all required params should be present in the Map sent to
+ * During the onExecuteListener handling, all required params should be present in the Map sent to
  * the listener. If they are not for some reason, this is an internal error.
  */
 public final class MissingRequiredArgException extends Exception {
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Entity.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Entity.kt
index 4db410c..b1d84c8 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Entity.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Entity.kt
@@ -17,7 +17,7 @@
 package androidx.appactions.interaction.capabilities.core.properties
 
 /**
- * Entities are used defining possible values for [ParamProperty].
+ * Entities are used defining possible values for [Property].
  */
 class Entity internal constructor(
     val id: String?,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/ParamProperty.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/ParamProperty.kt
deleted file mode 100644
index 6f9cbef..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/ParamProperty.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.properties
-
-/**
- * Base class for the property which describes a parameter for {@code Capability}. This class
- * should not be used directly. Instead, use the typed property classes such as {@link
- * StringProperty}, etc.
- *
- */
-sealed interface ParamProperty<V> {
-
-    /** The current list of possible values for this parameter, can change over time. */
-    val possibleValues: List<V>
-
-    /** Indicates that a value for this property is required to be present for fulfillment. */
-    val isRequired: Boolean
-
-    /**
-     * Indicates that a match of possible value for the given property must be present. Defaults to
-     * false.
-     *
-     * <p>If true, Assistant skips the capability if there is no match.
-     */
-    val isValueMatchRequired: Boolean
-
-    /**
-     * If true, the {@code Capability} will be rejected by assistant if corresponding param is
-     * set in argument. And the value of |isRequired| and |entityMatchRequired| will also be ignored
-     * by assistant.
-     */
-    val isProhibited: Boolean
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Property.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Property.kt
new file mode 100644
index 0000000..c338ec9
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Property.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.capabilities.core.properties
+
+/**
+ * Configure parameters for the capability such as providing possible values of some type, or
+ * marking a parameter as required for execution.
+ */
+class Property<T>
+internal constructor(
+    private val possibleValueSupplier: () -> List<T>,
+    /** Indicates that a value for this property is required to be present for fulfillment. */
+    @get:JvmName("isRequired")
+    val isRequired: Boolean,
+    /**
+     * Indicates that a match of possible value for the given property must be present. Defaults to
+     * false.
+     *
+     * <p>If true, Assistant skips the capability if there is no match.
+     */
+    @get:JvmName("isValueMatchRequired")
+    val isValueMatchRequired: Boolean,
+    /**
+     * If true, the {@code Capability} will be rejected by assistant if corresponding param is set
+     * in argument. And the value of |isRequired| and |entityMatchRequired| will also be ignored by
+     * assistant.
+     */
+    @get:JvmName("isProhibited")
+    val isProhibited: Boolean
+) {
+    /** The current list of possible values for this parameter, can change over time. */
+    val possibleValues: List<T>
+        get() = possibleValueSupplier()
+
+    /** Builder for {@link Property}. */
+    class Builder<T> {
+        private var possibleValueSupplier: () -> List<T> = { emptyList() }
+        private var isRequired = false
+        private var isValueMatchRequired = false
+
+        /**
+         * Sets one or more possible values for this parameter.
+         *
+         * @param values the possible values.
+         */
+        fun setPossibleValues(vararg values: T) = apply {
+            this.possibleValueSupplier = { values.asList() }
+        }
+
+        /**
+         * Sets a supplier of possible values for this parameter.
+         *
+         * @param supplier the supplier of possible values.
+         */
+        fun setPossibleValueSupplier(supplier: () -> List<T>) = apply {
+            this.possibleValueSupplier = supplier
+        }
+
+        /** Sets whether or not this property requires a value for fulfillment. */
+        fun setRequired(required: Boolean) = apply { this.isRequired = required }
+
+        /**
+         * Sets whether or not this property requires that the value for this property must match
+         * one of the Entity in the defined possible entities.
+         */
+        fun setValueMatchRequired(valueMatchRequired: Boolean) = apply {
+            this.isValueMatchRequired = valueMatchRequired
+        }
+
+        /** Builds the property for this entity parameter. */
+        fun build() =
+            Property(
+                this.possibleValueSupplier,
+                this.isRequired,
+                this.isValueMatchRequired,
+                isProhibited = false,
+            )
+    }
+
+    companion object {
+        @JvmStatic
+        fun <T> prohibited(): Property<T> {
+            return Property(
+                possibleValueSupplier = { emptyList() },
+                isRequired = false,
+                isValueMatchRequired = false,
+                isProhibited = true,
+            )
+        }
+    }
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/StringValue.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/StringValue.kt
index fbe5bef..bddf67d 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/StringValue.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/StringValue.kt
@@ -17,7 +17,7 @@
 package androidx.appactions.interaction.capabilities.core.properties
 
 /**
- * One of the possible possible values for [ParamProperty].
+ * One of the possible possible values for [Property].
  */
 class StringValue internal constructor(
     val name: String,
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/TypeProperty.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/TypeProperty.kt
deleted file mode 100644
index 917e135..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/TypeProperty.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.properties
-
-/** The property which describes a complex type. */
-class TypeProperty<T> internal constructor(
-    private val possibleValueSupplier: () -> List<T>,
-    override val isRequired: Boolean,
-    override val isValueMatchRequired: Boolean,
-    override val isProhibited: Boolean,
-) : ParamProperty<T> {
-    override val possibleValues: List<T>
-        get() = possibleValueSupplier()
-
-    /** Builder for {@link TypeProperty}. */
-    class Builder<T> {
-        private var possibleValueSupplier: () -> List<T> = { emptyList<T>() }
-        private var isRequired = false
-        private var isValueMatchRequired = false
-        private var isProhibited = false
-
-        /**
-         * Sets one or more possible values for this parameter.
-         *
-         * @param values the possible values.
-         */
-        fun setPossibleValues(vararg values: T) = apply {
-            this.possibleValueSupplier = { values.asList() }
-        }
-
-        /**
-         * Sets a supplier of possible values for this parameter.
-         *
-         * @param supplier the supplier of possible values.
-         */
-        fun setPossibleValueSupplier(supplier: () -> List<T>) = apply {
-            this.possibleValueSupplier = supplier
-        }
-
-        /** Sets whether or not this property requires a value for fulfillment. */
-        fun setRequired(isRequired: Boolean) = apply {
-            this.isRequired = isRequired
-        }
-
-        /**
-         * Sets whether or not this property requires that the value for this property must match
-         * one of
-         * the Entity in the defined possible entities.
-         */
-        fun setValueMatchRequired(isValueMatchRequired: Boolean) = apply {
-            this.isValueMatchRequired = isValueMatchRequired
-        }
-
-        /**
-         * Sets whether this property is prohibited in the response.
-         *
-         * @param isProhibited Whether this property is prohibited in the response.
-         */
-        fun setProhibited(isProhibited: Boolean) = apply {
-            this.isProhibited = isProhibited
-        }
-
-        /** Builds the property for this entity parameter. */
-        fun build() = TypeProperty(
-            this.possibleValueSupplier,
-            this.isRequired,
-            this.isValueMatchRequired,
-            this.isProhibited,
-        )
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Order.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Order.java
deleted file mode 100644
index 2f44202..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Order.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.values;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
-
-import com.google.auto.value.AutoValue;
-
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-/** Represents an order object. */
-@SuppressWarnings("AutoValueImmutableFields")
-@AutoValue
-public abstract class Order extends Thing {
-
-    /** Create a new Order.Builder instance. */
-    @NonNull
-    public static Builder newBuilder() {
-        return new AutoValue_Order.Builder();
-    }
-
-    /** Returns the date the order was placed. */
-    @NonNull
-    public abstract Optional<ZonedDateTime> getOrderDate();
-
-    /** Returns the {@link OrderItem}s in the order. */
-    @NonNull
-    public abstract List<OrderItem> getOrderedItems();
-
-    /** Returns the current status of the order. */
-    @NonNull
-    public abstract Optional<OrderStatus> getOrderStatus();
-
-    /** Returns the name of the seller. */
-    @NonNull
-    public abstract Optional<Organization> getSeller();
-
-    /** Returns the delivery information. */
-    @NonNull
-    public abstract Optional<ParcelDelivery> getOrderDelivery();
-
-    /** Status of the order. */
-    public enum OrderStatus {
-        ORDER_CANCELED("OrderCanceled"),
-        ORDER_DELIVERED("OrderDelivered"),
-        ORDER_IN_TRANSIT("OrderInTransit"),
-        ORDER_PAYMENT_DUE("OrderPaymentDue"),
-        ORDER_PICKUP_AVAILABLE("OrderPickupAvailable"),
-        ORDER_PROBLEM("OrderProblem"),
-        ORDER_PROCESSING("OrderProcessing"),
-        ORDER_RETURNED("OrderReturned");
-
-        private final String mStringValue;
-
-        OrderStatus(String stringValue) {
-            this.mStringValue = stringValue;
-        }
-
-        @Override
-        public String toString() {
-            return mStringValue;
-        }
-    }
-
-    /** Builder class for building an Order. */
-    @AutoValue.Builder
-    public abstract static class Builder extends Thing.Builder<Builder> implements
-            BuilderOf<Order> {
-
-        /** Order items to build. */
-        private final List<OrderItem> mOrderItems = new ArrayList<>();
-
-        /** Sets the date the order was placed. */
-        @NonNull
-        public abstract Builder setOrderDate(@NonNull ZonedDateTime orderDate);
-
-        /** Sets the ordered items. */
-        @NonNull
-        abstract Builder setOrderedItems(@NonNull List<OrderItem> orderItems);
-
-        /** Adds an item to the order. */
-        @NonNull
-        public final Builder addOrderedItem(@NonNull OrderItem orderItem) {
-            mOrderItems.add(orderItem);
-            return this;
-        }
-
-        /** Add a list of OrderItem. */
-        @NonNull
-        public final Builder addAllOrderedItems(@NonNull List<OrderItem> orderItems) {
-            this.mOrderItems.addAll(orderItems);
-            return this;
-        }
-
-        /** Sets the current order status. */
-        @NonNull
-        public abstract Builder setOrderStatus(@NonNull OrderStatus orderStatus);
-
-        /** Sets the name of the seller. */
-        @NonNull
-        public abstract Builder setSeller(@NonNull Organization seller);
-
-        /** Sets the order delivery. */
-        @NonNull
-        public abstract Builder setOrderDelivery(@NonNull ParcelDelivery parcelDelivery);
-
-        /** Builds and returns the Order instance. */
-        @Override
-        @NonNull
-        public final Order build() {
-            setOrderedItems(mOrderItems);
-            return autoBuild();
-        }
-
-        @NonNull
-        abstract Order autoBuild();
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/OrderItem.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/OrderItem.java
deleted file mode 100644
index 0475268..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/OrderItem.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.values;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
-
-import com.google.auto.value.AutoValue;
-
-/** Represents an item in an order. */
-@AutoValue
-public abstract class OrderItem extends Thing {
-
-    /** Create a new OrderItem.Builder instance. */
-    @NonNull
-    public static Builder newBuilder() {
-        return new AutoValue_OrderItem.Builder();
-    }
-
-    /** Builder class for building an OrderItem. */
-    @AutoValue.Builder
-    public abstract static class Builder extends Thing.Builder<Builder>
-            implements BuilderOf<OrderItem> {
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Organization.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Organization.java
deleted file mode 100644
index 9f5171a..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/Organization.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.values;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
-
-import com.google.auto.value.AutoValue;
-
-/** Represents an organization. */
-@AutoValue
-public abstract class Organization extends Thing {
-
-    /** Create a new Organization.Builder instance. */
-    @NonNull
-    public static Builder newBuilder() {
-        return new AutoValue_Organization.Builder();
-    }
-
-    /** Builder class for building an Organization. */
-    @AutoValue.Builder
-    public abstract static class Builder extends Thing.Builder<Builder>
-            implements BuilderOf<Organization> {
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/ParcelDelivery.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/ParcelDelivery.java
deleted file mode 100644
index a2437cd..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/values/ParcelDelivery.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.values;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
-
-import com.google.auto.value.AutoValue;
-
-import java.time.ZonedDateTime;
-import java.util.Optional;
-
-/** The delivery of a parcel. */
-@AutoValue
-public abstract class ParcelDelivery extends Thing {
-
-    /** Create a new ParcelDelivery.Builder instance. */
-    @NonNull
-    public static Builder newBuilder() {
-        return new AutoValue_ParcelDelivery.Builder();
-    }
-
-    /** Returns the delivery address. */
-    @NonNull
-    public abstract Optional<String> getDeliveryAddress();
-
-    /** Returns the method used for delivery or shipping. */
-    @NonNull
-    public abstract Optional<String> getDeliveryMethod();
-
-    /** Returns the earliest date the package may arrive. */
-    @NonNull
-    public abstract Optional<ZonedDateTime> getExpectedArrivalFrom();
-
-    /** Returns the latest date the package may arrive. */
-    @NonNull
-    public abstract Optional<ZonedDateTime> getExpectedArrivalUntil();
-
-    /** Returns the tracking number. */
-    @NonNull
-    public abstract Optional<String> getTrackingNumber();
-
-    /** Returns the tracking URL. */
-    @NonNull
-    public abstract Optional<String> getTrackingUrl();
-
-    /** Builder class for building ParcelDelivery. */
-    @AutoValue.Builder
-    public abstract static class Builder extends Thing.Builder<Builder>
-            implements BuilderOf<ParcelDelivery> {
-
-        /** Sets the delivery address. */
-        @NonNull
-        public abstract Builder setDeliveryAddress(@NonNull String deliveryAddress);
-
-        /** Sets the delivery method. */
-        @NonNull
-        public abstract Builder setDeliveryMethod(@NonNull String deliveryMethod);
-
-        /** Sets the earliest date the package may arrive. */
-        @NonNull
-        public abstract Builder setExpectedArrivalFrom(@NonNull ZonedDateTime expectedArrivalFrom);
-
-        /** Sets the latest date the package may arrive. */
-        @NonNull
-        public abstract Builder setExpectedArrivalUntil(
-                @NonNull ZonedDateTime expectedArrivalUntil);
-
-        /** Sets the tracking number. */
-        @NonNull
-        public abstract Builder setTrackingNumber(@NonNull String trackingNumber);
-
-        /** Sets the tracking URL. */
-        @NonNull
-        public abstract Builder setTrackingUrl(@NonNull String trackingUrl);
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/OrderProvider.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
similarity index 72%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/OrderProvider.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
index cbadad4..b412f34 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/OrderProvider.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
@@ -17,14 +17,13 @@
 package androidx.appactions.interaction.capabilities.core.entity
 
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
-import androidx.appactions.interaction.capabilities.core.values.Order
+import androidx.appactions.interaction.capabilities.core.values.Alarm
 
 /**  Internal testing object for entity provider */
-class OrderProvider internal constructor(
-    private var id: String,
-    private var response: EntityLookupResponse<Order>,
-) : EntityProvider<Order>(TypeConverters.ORDER_TYPE_SPEC) {
-    override fun getId(): String = id
-    override suspend fun lookup(request: EntityLookupRequest<Order>):
-        EntityLookupResponse<Order> = response
+class AlarmProvider internal constructor(
+    override val id: String,
+    private var response: EntityLookupResponse<Alarm>,
+) : EntityProvider<Alarm>(TypeConverters.ALARM_TYPE_SPEC) {
+    override suspend fun lookup(request: EntityLookupRequest<Alarm>):
+        EntityLookupResponse<Alarm> = response
 }
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
index 42fab86..b7a58e7 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/EntityProviderTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.appactions.interaction.capabilities.core.entity
 
-import androidx.appactions.interaction.capabilities.core.values.Order
+import androidx.appactions.interaction.capabilities.core.values.Alarm
 import androidx.appactions.interaction.proto.Entity
 import androidx.appactions.interaction.proto.GroundingRequest
 import androidx.appactions.interaction.proto.GroundingResponse
@@ -49,7 +49,7 @@
                                             .putFields(
                                                 "@type",
                                                 Value.newBuilder()
-                                                    .setStringValue("Order")
+                                                    .setStringValue("Alarm")
                                                     .build(),
                                             ),
                                     )
@@ -63,10 +63,10 @@
 @RunWith(JUnit4::class)
 class EntityProviderTest {
     private fun createExternalResponse(
-        candidateList: List<EntityLookupCandidate<Order>>,
+        candidateList: List<EntityLookupCandidate<Alarm>>,
         status: Int,
-    ): EntityLookupResponse<Order> {
-        return EntityLookupResponse.Builder<Order>()
+    ): EntityLookupResponse<Alarm> {
+        return EntityLookupResponse.Builder<Alarm>()
             .setCandidateList(candidateList)
             .setStatus(status)
             .setNextPageToken(ByteString.EMPTY)
@@ -83,10 +83,10 @@
         ).build()
     }
 
-    private fun createExternalCandidate(id: String, name: String): EntityLookupCandidate<Order> {
-        val candidateBuilder: EntityLookupCandidate.Builder<Order> =
+    private fun createExternalCandidate(id: String, name: String): EntityLookupCandidate<Alarm> {
+        val candidateBuilder: EntityLookupCandidate.Builder<Alarm> =
             EntityLookupCandidate.Builder()
-        candidateBuilder.setCandidate(Order.newBuilder().setName(name).setId(id).build())
+        candidateBuilder.setCandidate(Alarm.newBuilder().setName(name).setId(id).build())
         return candidateBuilder.build()
     }
 
@@ -97,7 +97,7 @@
                     .setIdentifier(id)
                     .setStructValue(
                         Struct.newBuilder()
-                            .putFields("@type", Value.newBuilder().setStringValue("Order").build())
+                            .putFields("@type", Value.newBuilder().setStringValue("Alarm").build())
                             .putFields("identifier", Value.newBuilder().setStringValue(id).build())
                             .putFields("name", Value.newBuilder().setStringValue(name).build()),
                     ),
@@ -107,7 +107,7 @@
 
     @Test
     fun invalidEntity_returnError() = runBlocking<Unit> {
-        val entityProvider = OrderProvider(
+        val entityProvider = AlarmProvider(
             "id",
             createExternalResponse(
                 listOf(),
@@ -129,7 +129,7 @@
 
     @Test
     fun errorInExternalResponse_returnError() = runBlocking<Unit> {
-        val entityProvider = OrderProvider(
+        val entityProvider = AlarmProvider(
             "id",
             createExternalResponse(
                 listOf(),
@@ -146,10 +146,10 @@
 
     @Test
     fun success() = runBlocking<Unit> {
-        val candidateBuilder: EntityLookupCandidate.Builder<Order> =
+        val candidateBuilder: EntityLookupCandidate.Builder<Alarm> =
             EntityLookupCandidate.Builder()
-        candidateBuilder.setCandidate(Order.newBuilder().setName("testing-order").build())
-        val entityProvider = OrderProvider(
+        candidateBuilder.setCandidate(Alarm.newBuilder().setName("testing-alarm").build())
+        val entityProvider = AlarmProvider(
             "id",
             createExternalResponse(
                 listOf(
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
index e60792a..26b6158 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
@@ -19,7 +19,7 @@
 import android.util.SizeF
 import androidx.appactions.interaction.capabilities.core.ActionExecutor
 import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync
-import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync.Companion.toActionExecutorAsync
+import androidx.appactions.interaction.capabilities.core.toActionExecutor
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.HostProperties
 import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures
@@ -27,15 +27,14 @@
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.Entity
-import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils
 import androidx.appactions.interaction.capabilities.testing.internal.FakeCallbackInternal
 import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.CB_TIMEOUT
 import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.BLOCKING_TIMEOUT
-import androidx.appactions.interaction.capabilities.core.testing.spec.Argument
+import androidx.appactions.interaction.capabilities.core.testing.spec.Arguments
 import androidx.appactions.interaction.capabilities.core.testing.spec.Output
-import androidx.appactions.interaction.capabilities.core.testing.spec.Property
+import androidx.appactions.interaction.capabilities.core.testing.spec.Properties
 import androidx.appactions.interaction.proto.FulfillmentResponse
 import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput
 import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput.OutputValue
@@ -44,6 +43,7 @@
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withTimeoutOrNull
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -57,7 +57,7 @@
     @Test
     fun oneShotCapability_successWithOutput() {
         val actionExecutor =
-            ActionExecutor<Argument, Output> {
+            ActionExecutor<Arguments, Output> {
                 ExecutionResult.Builder<Output>()
                     .setOutput(
                         Output.builder().setOptionalStringField("stringOutput").build(),
@@ -69,15 +69,13 @@
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                    Property.newBuilder()
-                        .setRequiredEntityField(
-                            TypeProperty.Builder<Entity>().build(),
-                        )
-                        .setOptionalStringField(
-                            TypeProperty.Builder<StringValue>().setProhibited(true).build(),
-                        )
-                        .build(),
-                actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
+                Properties.newBuilder()
+                    .setRequiredEntityField(
+                        Property.Builder<Entity>().build(),
+                    )
+                    .setOptionalStringField(Property.prohibited())
+                    .build(),
+                actionExecutor = actionExecutor,
             )
 
         val capabilitySession = capability.createSession(fakeSessionId, hostProperties)
@@ -119,21 +117,19 @@
 
     @Test
     fun oneShotCapability_failure() {
-        val actionExecutor = ActionExecutor<Argument, Output> { throw IllegalStateException("") }
+        val actionExecutor = ActionExecutor<Arguments, Output> { throw IllegalStateException("") }
         val capability =
             SingleTurnCapabilityImpl(
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                    Property.newBuilder()
-                        .setRequiredEntityField(
-                            TypeProperty.Builder<Entity>().build(),
-                        )
-                        .setOptionalStringField(
-                            TypeProperty.Builder<StringValue>().setProhibited(true).build(),
-                        )
-                        .build(),
-                actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
+                Properties.newBuilder()
+                    .setRequiredEntityField(
+                        Property.Builder<Entity>().build(),
+                    )
+                    .setOptionalStringField(Property.prohibited())
+                    .build(),
+                actionExecutor = actionExecutor,
             )
 
         val capabilitySession = capability.createSession(fakeSessionId, hostProperties)
@@ -156,18 +152,18 @@
     @Test
     fun oneShotSession_uiHandle_withActionExecutor() {
         val actionExecutor =
-            ActionExecutor<Argument, Output> { ExecutionResult.getDefaultInstance() }
+            ActionExecutor<Arguments, Output> { ExecutionResult.Builder<Output>().build() }
         val capability =
             SingleTurnCapabilityImpl(
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                Property.newBuilder()
+                Properties.newBuilder()
                     .setRequiredEntityField(
-                        TypeProperty.Builder<Entity>().build(),
+                        Property.Builder<Entity>().build(),
                     )
                     .build(),
-                actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
+                actionExecutor = actionExecutor,
             )
         val session = capability.createSession(fakeSessionId, hostProperties)
         assertThat(session.uiHandle).isSameInstanceAs(actionExecutor)
@@ -176,41 +172,42 @@
     @Test
     fun oneShotSession_uiHandle_withActionExecutorAsync() {
         val actionExecutorAsync =
-            ActionExecutorAsync<Argument, Output> {
-                Futures.immediateFuture(ExecutionResult.getDefaultInstance())
+            ActionExecutorAsync<Arguments, Output> {
+                Futures.immediateFuture(ExecutionResult.Builder<Output>().build())
             }
         val capability =
             SingleTurnCapabilityImpl(
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                Property.newBuilder()
+                Properties.newBuilder()
                     .setRequiredEntityField(
-                        TypeProperty.Builder<Entity>().build(),
+                        Property.Builder<Entity>().build(),
                     )
                     .build(),
-                actionExecutorAsync = actionExecutorAsync,
+                actionExecutor = actionExecutorAsync.toActionExecutor(),
             )
         val session = capability.createSession(fakeSessionId, hostProperties)
         assertThat(session.uiHandle).isSameInstanceAs(actionExecutorAsync)
     }
 
+    @Ignore // b/277121577
     @Test
     fun multipleSessions_sequentialExecution(): Unit = runBlocking {
         val executionResultChannel = Channel<ExecutionResult<Output>>()
-        val argumentChannel = Channel<Argument>()
+        val argumentChannel = Channel<Arguments>()
 
-        val actionExecutor = ActionExecutor<Argument, Output> {
+        val actionExecutor = ActionExecutor<Arguments, Output> {
             argumentChannel.send(it)
             executionResultChannel.receive()
         }
         val capability = SingleTurnCapabilityImpl(
             id = "capabilityId",
             actionSpec = ACTION_SPEC,
-            property = Property.newBuilder().setRequiredEntityField(
-                TypeProperty.Builder<Entity>().build(),
+            property = Properties.newBuilder().setRequiredEntityField(
+                Property.Builder<Entity>().build(),
             ).build(),
-            actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
+            actionExecutor = actionExecutor,
         )
         val session1 = capability.createSession("session1", hostProperties)
         val session2 = capability.createSession("session2", hostProperties)
@@ -239,38 +236,38 @@
 
         // verify ActionExecutor receives 1st request.
         assertThat(argumentChannel.receive()).isEqualTo(
-            Argument.newBuilder().setOptionalStringField("string value 1").build(),
+            Arguments.newBuilder().setOptionalStringField("string value 1").build(),
         )
         // verify the 2nd request cannot be received due to mutex.
         assertThat(withTimeoutOrNull(BLOCKING_TIMEOUT) { argumentChannel.receive() }).isNull()
 
         // unblock first request handling.
-        executionResultChannel.send(ExecutionResult.getDefaultInstance())
+        executionResultChannel.send(ExecutionResult.Builder<Output>().build())
         assertThat(callbackInternal1.receiveResponse().fulfillmentResponse).isEqualTo(
             FulfillmentResponse.getDefaultInstance(),
         )
 
         assertThat(argumentChannel.receive()).isEqualTo(
-            Argument.newBuilder().setOptionalStringField("string value 2").build(),
+            Arguments.newBuilder().setOptionalStringField("string value 2").build(),
         )
-        executionResultChannel.send(ExecutionResult.getDefaultInstance())
+        executionResultChannel.send(ExecutionResult.Builder<Output>().build())
         assertThat(callbackInternal2.receiveResponse().fulfillmentResponse).isEqualTo(
             FulfillmentResponse.getDefaultInstance(),
         )
     }
 
     companion object {
-        val ACTION_SPEC: ActionSpec<Property, Argument, Output> =
+        val ACTION_SPEC: ActionSpec<Properties, Arguments, Output> =
             ActionSpecBuilder.ofCapabilityNamed(
                 "actions.intent.TEST",
             )
-                .setDescriptor(Property::class.java)
-                .setArgument(Argument::class.java, Argument::newBuilder)
+                .setDescriptor(Properties::class.java)
+                .setArguments(Arguments::class.java, Arguments::newBuilder)
                 .setOutput(Output::class.java)
                 .bindOptionalParameter(
                     "optionalString",
-                    Property::optionalStringField,
-                    Argument.Builder::setOptionalStringField,
+                    Properties::optionalStringField,
+                    Arguments.Builder::setOptionalStringField,
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     TypeConverters.STRING_VALUE_ENTITY_CONVERTER
                 )
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.java
deleted file mode 100644
index 3fd451a..0000000
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.core.impl.concurrent;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.testing.internal.SettableFutureWrapper;
-import androidx.test.filters.SdkSuppress;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.concurrent.ExecutionException;
-import java.util.function.Function;
-
-@RunWith(JUnit4.class)
-public final class FuturesTest {
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void addCallback_onSuccess() throws Exception {
-        SettableFutureWrapper<Integer> integerFutureWrapper = new SettableFutureWrapper<>();
-        SettableFutureWrapper<Boolean> testFutureWrapper = new SettableFutureWrapper<>();
-        Futures.addCallback(
-                integerFutureWrapper.getFuture(),
-                new FutureCallback<Integer>() {
-                    @Override
-                    public void onSuccess(Integer value) {
-                        assertThat(value).isEqualTo(25);
-                        testFutureWrapper.set(true);
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        testFutureWrapper.set(false);
-                    }
-                },
-                Runnable::run);
-
-        assertThat(testFutureWrapper.getFuture().isDone()).isFalse();
-        integerFutureWrapper.set(25);
-        assertThat(testFutureWrapper.getFuture().get()).isTrue();
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void addCallback_onFailure() throws Exception {
-        SettableFutureWrapper<Object> objectFutureWrapper = new SettableFutureWrapper<>();
-        SettableFutureWrapper<Boolean> testFutureWrapper = new SettableFutureWrapper<>();
-        Futures.addCallback(
-                objectFutureWrapper.getFuture(),
-                new FutureCallback<Object>() {
-                    @Override
-                    public void onSuccess(Object value) {
-                        testFutureWrapper.set(false);
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        assertThat(t).isInstanceOf(IllegalStateException.class);
-                        testFutureWrapper.set(true);
-                    }
-                },
-                Runnable::run);
-
-        assertThat(testFutureWrapper.getFuture().isDone()).isFalse();
-        objectFutureWrapper.setException(new IllegalStateException());
-        assertThat(testFutureWrapper.getFuture().get()).isTrue();
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void transform_success() throws Exception {
-        SettableFutureWrapper<Integer> integerFutureWrapper = new SettableFutureWrapper<>();
-        ListenableFuture<Integer> transformedFuture =
-                Futures.transform(
-                        integerFutureWrapper.getFuture(), (x) -> x + 10,
-                        Runnable::run,
-                        "add 10");
-
-        assertThat(transformedFuture.isDone()).isFalse();
-        integerFutureWrapper.set(25);
-        assertThat(transformedFuture.get()).isEqualTo(35);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void transformAsync_success() throws Exception {
-        SettableFutureWrapper<Integer> integerFutureWrapper = new SettableFutureWrapper<>();
-        ListenableFuture<Integer> transformedFuture =
-                Futures.transformAsync(
-                        integerFutureWrapper.getFuture(),
-                        (x) -> {
-                            SettableFutureWrapper<Integer> transformFuture =
-                                    new SettableFutureWrapper<>();
-                            transformFuture.set(x + 10);
-                            return transformFuture.getFuture();
-                        },
-                        Runnable::run,
-                        "add 10 async");
-
-        assertThat(transformedFuture.isDone()).isFalse();
-        integerFutureWrapper.set(25);
-        assertThat(transformedFuture.get()).isEqualTo(35);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void immediateFuture_success() throws Exception {
-        ListenableFuture<Integer> immediateFuture = Futures.immediateFuture(25);
-        immediateFuture.cancel(true);
-        assertThat(immediateFuture.isCancelled()).isFalse();
-        assertThat(immediateFuture.isDone()).isTrue();
-        assertThat(immediateFuture.get()).isEqualTo(25);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void immediateVoidFuture_success() throws Exception {
-        ListenableFuture<Void> immediateVoidFuture = Futures.immediateVoidFuture();
-        immediateVoidFuture.cancel(true);
-        assertThat(immediateVoidFuture.isCancelled()).isFalse();
-        assertThat(immediateVoidFuture.isDone()).isTrue();
-        assertThat(immediateVoidFuture.get()).isEqualTo(null);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void immediateFailedFuture_failure() throws Exception {
-        ListenableFuture<Object> immediateFailedFuture =
-                Futures.immediateFailedFuture(new CustomException());
-        ListenableFuture<Object> transformedFuture =
-                Futures.transform(immediateFailedFuture, Function.identity(), Runnable::run,
-                        "test");
-
-        assertThat(transformedFuture.isDone()).isTrue();
-        ExecutionException e = assertThrows(ExecutionException.class, transformedFuture::get);
-        assertThat(e).hasCauseThat().isInstanceOf(CustomException.class);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void transform_synchronousExceptionPropagated() throws Exception {
-        Function<Integer, Integer> badTransform =
-                (unused) -> {
-                    throw new IllegalStateException();
-                };
-        ListenableFuture<Integer> transformedFuture =
-                Futures.transform(Futures.immediateFuture(25), badTransform, Runnable::run,
-                        "badTransform");
-        assertThat(transformedFuture.isDone()).isTrue();
-
-        SettableFutureWrapper<Throwable> errorContainer = new SettableFutureWrapper<>();
-        Futures.addCallback(
-                transformedFuture,
-                new FutureCallback<Integer>() {
-                    @Override
-                    public void onSuccess(Integer value) {
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        errorContainer.set(t);
-                    }
-                },
-                Runnable::run);
-        assertThat(errorContainer.getFuture().get()).isInstanceOf(
-                IllegalStateException.class);
-        ExecutionException e = assertThrows(ExecutionException.class, transformedFuture::get);
-        assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void transformAsync_synchronousExceptionPropagated() throws Exception {
-        Function<Integer, ListenableFuture<Integer>> badAsyncTransform =
-                (unused) -> {
-                    throw new IllegalStateException();
-                };
-        ListenableFuture<Integer> transformedFuture =
-                Futures.transformAsync(
-                        Futures.immediateFuture(25), badAsyncTransform, Runnable::run,
-                        "badAsyncTransform");
-        assertThat(transformedFuture.isDone()).isTrue();
-
-        SettableFutureWrapper<Throwable> errorContainer = new SettableFutureWrapper<>();
-        Futures.addCallback(
-                transformedFuture,
-                new FutureCallback<Integer>() {
-                    @Override
-                    public void onSuccess(Integer value) {
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        errorContainer.set(t);
-                    }
-                },
-                Runnable::run);
-        assertThat(errorContainer.getFuture().get()).isInstanceOf(
-                IllegalStateException.class);
-        ExecutionException e = assertThrows(ExecutionException.class, transformedFuture::get);
-        assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException.class);
-    }
-
-    private static class CustomException extends Exception {
-    }
-}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.kt
new file mode 100644
index 0000000..6d9de02
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/concurrent/FuturesTest.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.capabilities.core.impl.concurrent
+
+import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.CB_TIMEOUT
+import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.awaitSync
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import androidx.concurrent.futures.CallbackToFutureAdapter.Completer
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit.MILLISECONDS
+
+@RunWith(JUnit4::class)
+class FuturesTest {
+    @Test
+    fun addCallback_onSuccess() {
+        lateinit var integerCompleter: Completer<Int>
+        val integerFuture = CallbackToFutureAdapter.getFuture<Int> {
+            integerCompleter = it
+            "integerFuture"
+        }
+        val calbackSuccessDeferred = CompletableDeferred<Boolean>()
+        Futures.addCallback(
+            integerFuture,
+            object : FutureCallback<Int> {
+                override fun onSuccess(result: Int) {
+                    calbackSuccessDeferred.complete(true)
+                }
+
+                override fun onFailure(t: Throwable) {
+                    calbackSuccessDeferred.complete(false)
+                }
+            },
+            Runnable::run,
+        )
+
+        assertThat(calbackSuccessDeferred.isCompleted).isFalse()
+
+        integerCompleter.set(25)
+
+        assertThat(calbackSuccessDeferred.awaitSync()).isTrue()
+    }
+
+    @Test
+    fun addCallback_onFailure() {
+        lateinit var integerCompleter: Completer<Int>
+        val integerFuture = CallbackToFutureAdapter.getFuture<Int> {
+            integerCompleter = it
+            "integerFuture"
+        }
+        val calbackSuccessDeferred = CompletableDeferred<Boolean>()
+        Futures.addCallback(
+            integerFuture,
+            object : FutureCallback<Int> {
+                override fun onSuccess(result: Int) {
+                    calbackSuccessDeferred.complete(true)
+                }
+
+                override fun onFailure(t: Throwable) {
+                    calbackSuccessDeferred.complete(false)
+                }
+            },
+            Runnable::run,
+        )
+
+        assertThat(calbackSuccessDeferred.isCompleted).isFalse()
+
+        integerCompleter.setException(IllegalStateException())
+
+        assertThat(calbackSuccessDeferred.awaitSync()).isFalse()
+    }
+
+    @Test
+    fun transform_success() {
+        lateinit var integerCompleter: Completer<Int>
+        val integerFuture = CallbackToFutureAdapter.getFuture<Int> {
+            integerCompleter = it
+            "integerFuture"
+        }
+        val transformedFuture = Futures.transform(
+            integerFuture,
+            { it + 10 },
+            Runnable::run,
+            "add 10",
+        )
+        integerCompleter.set(25)
+        assertThat(transformedFuture.get(CB_TIMEOUT, MILLISECONDS)).isEqualTo(35)
+    }
+
+    @Test
+    fun transformAsync_success() {
+        lateinit var integerCompleter: Completer<Int>
+        val integerFuture = CallbackToFutureAdapter.getFuture<Int> {
+            integerCompleter = it
+            "integerFuture"
+        }
+        val transformedFuture = Futures.transformAsync(
+            integerFuture,
+            { Futures.immediateFuture(it + 10) },
+            Runnable::run,
+            "add 10",
+        )
+        integerCompleter.set(25)
+        assertThat(transformedFuture.get(CB_TIMEOUT, MILLISECONDS)).isEqualTo(35)
+    }
+
+    @Test
+    fun immediateFuture_success() {
+        val immediateFuture = Futures.immediateFuture(25)
+        immediateFuture.cancel(true)
+        assertThat(immediateFuture.isCancelled()).isFalse()
+        assertThat(immediateFuture.isDone()).isTrue()
+        assertThat(immediateFuture.get(CB_TIMEOUT, MILLISECONDS)).isEqualTo(25)
+    }
+
+    @Test
+    fun immediateVoidFuture_success() {
+        val immediateVoidFuture = Futures.immediateVoidFuture()
+        immediateVoidFuture.cancel(true)
+        assertThat(immediateVoidFuture.isCancelled()).isFalse()
+        assertThat(immediateVoidFuture.isDone()).isTrue()
+        assertThat(immediateVoidFuture.get(CB_TIMEOUT, MILLISECONDS)).isNull()
+    }
+
+    @Test
+    fun immediateFailedFuture_failure() {
+        val immediateFailedFuture =
+            Futures.immediateFailedFuture<Any>(CustomException())
+        val transformedFuture =
+            Futures.transform(
+                immediateFailedFuture,
+                { it },
+                Runnable::run,
+                "test",
+            )
+
+        assertThat(transformedFuture.isDone()).isTrue()
+        val e = assertThrows(ExecutionException::class.java, transformedFuture::get)
+        assertThat(e).hasCauseThat().isInstanceOf(CustomException::class.java)
+    }
+
+    @Test
+    fun transform_synchronousExceptionPropagated() {
+        val transformedFuture =
+            Futures.transform(
+                Futures.immediateFuture(25),
+                { throw IllegalStateException() },
+                Runnable::run,
+                "badTransform",
+            )
+        assertThat(transformedFuture.isDone()).isTrue()
+
+        val errorDeferred = CompletableDeferred<Throwable>()
+        Futures.addCallback(
+            transformedFuture,
+            object : FutureCallback<Int> {
+                override fun onSuccess(value: Int) {}
+
+                override fun onFailure(t: Throwable) {
+                    errorDeferred.complete(t)
+                }
+            },
+            Runnable::run,
+        )
+        assertThat(errorDeferred.awaitSync()).isInstanceOf(
+            IllegalStateException::class.java,
+        )
+        val e = assertThrows(ExecutionException::class.java, transformedFuture::get)
+        assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException::class.java)
+    }
+
+    @Test
+    fun transformAsync_synchronousExceptionPropagated() {
+        val transformedFuture =
+            Futures.transformAsync<Int, Int>(
+                Futures.immediateFuture(25),
+                { throw IllegalStateException() },
+                Runnable::run,
+                "badTransform",
+            )
+        assertThat(transformedFuture.isDone()).isTrue()
+
+        val errorDeferred = CompletableDeferred<Throwable>()
+        Futures.addCallback(
+            transformedFuture,
+            object : FutureCallback<Int> {
+                override fun onSuccess(value: Int) {}
+
+                override fun onFailure(t: Throwable) {
+                    errorDeferred.complete(t)
+                }
+            },
+            Runnable::run,
+        )
+        assertThat(errorDeferred.awaitSync()).isInstanceOf(
+            IllegalStateException::class.java,
+        )
+        val e = assertThrows(ExecutionException::class.java, transformedFuture::get)
+        assertThat(e).hasCauseThat().isInstanceOf(IllegalStateException::class.java)
+    }
+
+    class CustomException : Exception()
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
index 88159c2..dd78f17 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeConvertersTest.java
@@ -22,7 +22,6 @@
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.ITEM_LIST_TYPE_SPEC;
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.LIST_ITEM_TYPE_SPEC;
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.MESSAGE_TYPE_SPEC;
-import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.ORDER_TYPE_SPEC;
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.PARTICIPANT_TYPE_SPEC;
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.RECIPIENT_TYPE_SPEC;
 import static androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.SAFETY_CHECK_TYPE_SPEC;
@@ -39,10 +38,6 @@
 import androidx.appactions.interaction.capabilities.core.values.ItemList;
 import androidx.appactions.interaction.capabilities.core.values.ListItem;
 import androidx.appactions.interaction.capabilities.core.values.Message;
-import androidx.appactions.interaction.capabilities.core.values.Order;
-import androidx.appactions.interaction.capabilities.core.values.OrderItem;
-import androidx.appactions.interaction.capabilities.core.values.Organization;
-import androidx.appactions.interaction.capabilities.core.values.ParcelDelivery;
 import androidx.appactions.interaction.capabilities.core.values.Person;
 import androidx.appactions.interaction.capabilities.core.values.SafetyCheck;
 import androidx.appactions.interaction.capabilities.core.values.SearchAction;
@@ -75,23 +70,6 @@
         return Value.newBuilder().setStructValue(struct).build();
     }
 
-    private static final Order ORDER_JAVA_THING =
-            Order.newBuilder()
-                    .setId("id")
-                    .setName("name")
-                    .addOrderedItem(OrderItem.newBuilder().setName("apples").build())
-                    .addOrderedItem(OrderItem.newBuilder().setName("oranges").build())
-                    .setSeller(Organization.newBuilder().setName("Google").build())
-                    .setOrderDate(ZonedDateTime.of(2022, 1, 1, 8, 0, 0, 0, ZoneOffset.UTC))
-                    .setOrderStatus(Order.OrderStatus.ORDER_DELIVERED)
-                    .setOrderDelivery(
-                            ParcelDelivery.newBuilder()
-                                    .setDeliveryAddress("test address")
-                                    .setDeliveryMethod("UPS")
-                                    .setTrackingNumber("A12345")
-                                    .setTrackingUrl("https://")
-                                    .build())
-                    .build();
     private static final Person PERSON_JAVA_THING =
             Person.newBuilder()
                     .setName("name")
@@ -125,77 +103,7 @@
                     .setDuration(Duration.ofMinutes(5))
                     .setCheckinTime(ZonedDateTime.of(2023, 01, 10, 10, 0, 0, 0, ZoneOffset.UTC))
                     .build();
-    private static final ListValue ORDER_ITEMS_STRUCT =
-            ListValue.newBuilder()
-                    .addValues(
-                            Value.newBuilder()
-                                    .setStructValue(
-                                            Struct.newBuilder()
-                                                    .putFields(
-                                                            "@type",
-                                                            Value.newBuilder()
-                                                                    .setStringValue("OrderItem")
-                                                                    .build())
-                                                    .putFields(
-                                                            "name",
-                                                            Value.newBuilder()
-                                                                    .setStringValue("apples")
-                                                                    .build()))
-                                    .build())
-                    .addValues(
-                            Value.newBuilder()
-                                    .setStructValue(
-                                            Struct.newBuilder()
-                                                    .putFields(
-                                                            "@type",
-                                                            Value.newBuilder()
-                                                                    .setStringValue("OrderItem")
-                                                                    .build())
-                                                    .putFields(
-                                                            "name",
-                                                            Value.newBuilder()
-                                                                    .setStringValue("oranges")
-                                                                    .build()))
-                                    .build())
-                    .build();
-    private static final Struct PARCEL_DELIVERY_STRUCT =
-            Struct.newBuilder()
-                    .putFields("@type", Value.newBuilder().setStringValue("ParcelDelivery").build())
-                    .putFields(
-                            "deliveryAddress",
-                            Value.newBuilder().setStringValue("test address").build())
-                    .putFields(
-                            "hasDeliveryMethod", Value.newBuilder().setStringValue("UPS").build())
-                    .putFields(
-                            "trackingNumber", Value.newBuilder().setStringValue("A12345").build())
-                    .putFields("trackingUrl", Value.newBuilder().setStringValue("https://").build())
-                    .build();
-    private static final Struct ORGANIZATION_STRUCT =
-            Struct.newBuilder()
-                    .putFields("@type", Value.newBuilder().setStringValue("Organization").build())
-                    .putFields("name", Value.newBuilder().setStringValue("Google").build())
-                    .build();
-    private static final Struct ORDER_STRUCT =
-            Struct.newBuilder()
-                    .putFields("@type", Value.newBuilder().setStringValue("Order").build())
-                    .putFields("identifier", Value.newBuilder().setStringValue("id").build())
-                    .putFields("name", Value.newBuilder().setStringValue("name").build())
-                    .putFields(
-                            "orderDate",
-                            Value.newBuilder().setStringValue("2022-01-01T08:00Z").build())
-                    .putFields(
-                            "orderDelivery",
-                            Value.newBuilder().setStructValue(PARCEL_DELIVERY_STRUCT).build())
-                    .putFields(
-                            "orderedItem",
-                            Value.newBuilder().setListValue(ORDER_ITEMS_STRUCT).build())
-                    .putFields(
-                            "orderStatus",
-                            Value.newBuilder().setStringValue("OrderDelivered").build())
-                    .putFields(
-                            "seller",
-                            Value.newBuilder().setStructValue(ORGANIZATION_STRUCT).build())
-                    .build();
+
     private static final Struct PERSON_STRUCT =
             Struct.newBuilder()
                     .putFields("@type", Value.newBuilder().setStringValue("Person").build())
@@ -283,10 +191,6 @@
         return ParamValue.newBuilder().setIdentifier(identifier).setStructValue(struct).build();
     }
 
-    private static Entity toEntity(Struct struct) {
-        return Entity.newBuilder().setIdentifier("id").setStructValue(struct).build();
-    }
-
     @Test
     public void toEntityValue() throws Exception {
         List<ParamValue> input =
@@ -464,19 +368,6 @@
     }
 
     @Test
-    public void order_conversions_matchesExpected() throws Exception {
-        EntityConverter<Order> entityConverter = EntityConverter.Companion.of(ORDER_TYPE_SPEC);
-        ParamValueConverter<Order> paramValueConverter =
-                ParamValueConverter.Companion.of(ORDER_TYPE_SPEC);
-
-        assertThat(paramValueConverter.toParamValue(ORDER_JAVA_THING))
-                .isEqualTo(toParamValue(ORDER_STRUCT, "id"));
-        assertThat(paramValueConverter.fromParamValue(toParamValue(ORDER_STRUCT, "id")))
-                .isEqualTo(ORDER_JAVA_THING);
-        assertThat(entityConverter.convert(ORDER_JAVA_THING)).isEqualTo(toEntity(ORDER_STRUCT));
-    }
-
-    @Test
     public void participant_conversions_matchesExpected() throws Exception {
         ParamValueConverter<Participant> paramValueConverter =
                 ParamValueConverter.Companion.of(PARTICIPANT_TYPE_SPEC);
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImplTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImplTest.java
index 73568b6..9200696 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImplTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/converters/TypeSpecImplTest.java
@@ -20,6 +20,8 @@
 
 import static org.junit.Assert.assertThrows;
 
+import androidx.appactions.builtintypes.properties.Name;
+import androidx.appactions.builtintypes.types.Thing;
 import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
 import androidx.appactions.interaction.capabilities.core.testing.spec.TestEntity;
 import androidx.appactions.interaction.protobuf.Struct;
@@ -298,4 +300,32 @@
         assertThrows(
                 StructConversionException.class, () -> entityTypeSpec.fromValue(malformedValue));
     }
+
+    @Test
+    public void newBuilderForThing_builtInTypes_smokeTest() throws Exception {
+        TypeSpec<Thing> thingTypeSpec =
+                TypeSpecBuilder.newBuilderForThing("Thing", Thing::Builder, Thing.Builder::build)
+                        .build();
+
+        Thing thing = Thing.Builder().setIdentifier("thing").setName(new Name("Thing One")).build();
+        Value thingValue =
+                structToValue(
+                        Struct.newBuilder()
+                                .putFields(
+                                        "@type", Value.newBuilder().setStringValue("Thing").build())
+                                .putFields(
+                                        "identifier",
+                                        Value.newBuilder().setStringValue("thing").build())
+                                .putFields(
+                                        "name",
+                                        Value.newBuilder().setStringValue("Thing One").build())
+                                .build());
+
+        assertThat(thingTypeSpec.getIdentifier(thing)).isEqualTo("thing");
+        assertThat(thingTypeSpec.toValue(thing)).isEqualTo(thingValue);
+        assertThat(thingTypeSpec.fromValue(thingValue).getIdentifier())
+                .isEqualTo(thing.getIdentifier());
+        assertThat(thingTypeSpec.fromValue(thingValue).getName().asText())
+                .isEqualTo(thing.getName().asText());
+    }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
index 46e440c..23cf78f 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
@@ -24,8 +24,8 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter;
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters;
 import androidx.appactions.interaction.capabilities.core.properties.Entity;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
 import androidx.appactions.interaction.capabilities.core.testing.spec.Output;
 import androidx.appactions.interaction.capabilities.core.values.EntityValue;
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction;
@@ -46,45 +46,45 @@
 @RunWith(JUnit4.class)
 public final class ActionSpecTest {
 
-    private static final ActionSpec<Property, Argument, Output> ACTION_SPEC =
+    private static final ActionSpec<Properties, Arguments, Output> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed("actions.intent.TEST")
-                    .setDescriptor(Property.class)
-                    .setArgument(Argument.class, Argument::newBuilder)
+                    .setDescriptor(Properties.class)
+                    .setArguments(Arguments.class, Arguments::newBuilder)
                     .setOutput(Output.class)
                     .bindParameter(
                             "requiredEntity",
-                            Property::requiredEntityField,
-                            Argument.Builder::setRequiredEntityField,
+                            Properties::requiredEntityField,
+                            Arguments.Builder::setRequiredEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "optionalEntity",
-                            Property::optionalEntityField,
-                            Argument.Builder::setOptionalEntityField,
+                            Properties::optionalEntityField,
+                            Arguments.Builder::setOptionalEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindRepeatedParameter(
                             "repeatedEntity",
-                            Property::repeatedEntityField,
-                            Argument.Builder::setRepeatedEntityField,
+                            Properties::repeatedEntityField,
+                            Arguments.Builder::setRepeatedEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindParameter(
                             "requiredString",
-                            Property::requiredStringField,
-                            Argument.Builder::setRequiredStringField,
+                            Properties::requiredStringField,
+                            Arguments.Builder::setRequiredStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "optionalString",
-                            Property::optionalStringField,
-                            Argument.Builder::setOptionalStringField,
+                            Properties::optionalStringField,
+                            Arguments.Builder::setOptionalStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindRepeatedParameter(
                             "repeatedString",
-                            Property::repeatedStringField,
-                            Argument.Builder::setRepeatedStringField,
+                            Properties::repeatedStringField,
+                            Arguments.Builder::setRepeatedStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindOptionalOutput(
@@ -116,27 +116,27 @@
                             .setName(theString)
                             .build();
 
-    private static final ActionSpec<GenericEntityProperty, GenericEntityArgument, Output>
+    private static final ActionSpec<GenericEntityProperty, GenericEntityArguments, Output>
             GENERIC_TYPES_ACTION_SPEC =
                     ActionSpecBuilder.ofCapabilityNamed("actions.intent.TEST")
                             .setDescriptor(GenericEntityProperty.class)
-                            .setArgument(
-                                    GenericEntityArgument.class, GenericEntityArgument::newBuilder)
+                            .setArguments(GenericEntityArguments.class,
+                                    GenericEntityArguments::newBuilder)
                             .setOutput(Output.class)
                             .bindParameter(
                                     "requiredEntity",
                                     GenericEntityProperty::singularField,
-                                    GenericEntityArgument.Builder::setSingularField,
+                                    GenericEntityArguments.Builder::setSingularField,
                                     STRING_PARAM_VALUE_CONVERTER,
                                     STRING_ENTITY_CONVERTER)
                             .bindOptionalParameter("optionalEntity",
                                     GenericEntityProperty::optionalField,
-                                    GenericEntityArgument.Builder::setOptionalField,
+                                    GenericEntityArguments.Builder::setOptionalField,
                                     STRING_PARAM_VALUE_CONVERTER,
                                     STRING_ENTITY_CONVERTER)
                             .bindRepeatedParameter("repeatedEntities",
                                     GenericEntityProperty::repeatedField,
-                                    GenericEntityArgument.Builder::setRepeatedField,
+                                    GenericEntityArguments.Builder::setRepeatedField,
                                     STRING_PARAM_VALUE_CONVERTER,
                                     STRING_ENTITY_CONVERTER)
                             .build();
@@ -145,17 +145,17 @@
     public void getAppAction_genericParameters() {
         GenericEntityProperty property =
                 GenericEntityProperty.create(
-                        new TypeProperty.Builder<String>()
+                        new Property.Builder<String>()
                                 .setRequired(true)
                                 .setPossibleValues("one")
                                 .build(),
                         Optional.of(
-                                new TypeProperty.Builder<String>()
+                                new Property.Builder<String>()
                                         .setRequired(true)
                                         .setPossibleValues("two")
                                         .build()),
                         Optional.of(
-                                new TypeProperty.Builder<String>()
+                                new Property.Builder<String>()
                                         .setRequired(true)
                                         .setPossibleValues("three")
                                         .build()));
@@ -196,9 +196,9 @@
 
     @Test
     public void getAppAction_onlyRequiredProperty() {
-        Property property =
-                Property.create(
-                        new TypeProperty.Builder<Entity>()
+        Properties property =
+                Properties.create(
+                        new Property.Builder<Entity>()
                                 .setPossibleValues(
                                         new Entity.Builder()
                                                 .setId("contact_2")
@@ -207,7 +207,7 @@
                                                 .build())
                                 .setValueMatchRequired(true)
                                 .build(),
-                        new TypeProperty.Builder<StringValue>().build());
+                        new Property.Builder<StringValue>().build());
 
         assertThat(ACTION_SPEC.convertPropertyToProto(property))
                 .isEqualTo(
@@ -231,9 +231,9 @@
 
     @Test
     public void getAppAction_allProperties() {
-        Property property =
-                Property.create(
-                        new TypeProperty.Builder<Entity>()
+        Properties property =
+                Properties.create(
+                        new Property.Builder<Entity>()
                                 .setPossibleValues(
                                         new Entity.Builder()
                                                 .setId("contact_2")
@@ -242,7 +242,7 @@
                                                 .build())
                                 .build(),
                         Optional.of(
-                                new TypeProperty.Builder<Entity>()
+                                new Property.Builder<Entity>()
                                         .setPossibleValues(
                                                 new Entity.Builder()
                                                         .setId("entity1")
@@ -251,12 +251,12 @@
                                         .setRequired(true)
                                         .build()),
                         Optional.of(
-                                new TypeProperty.Builder<TestEnum>()
+                                new Property.Builder<TestEnum>()
                                         .setPossibleValues(TestEnum.VALUE_1)
                                         .setRequired(true)
                                         .build()),
                         Optional.of(
-                                new TypeProperty.Builder<Entity>()
+                                new Property.Builder<Entity>()
                                         .setPossibleValues(
                                                 new Entity.Builder()
                                                         .setId("entity1")
@@ -268,17 +268,14 @@
                                                         .build())
                                         .setRequired(true)
                                         .build()),
-                        new TypeProperty.Builder<StringValue>().build(),
+                        new Property.Builder<StringValue>().build(),
                         Optional.of(
-                                new TypeProperty.Builder<StringValue>()
+                                new Property.Builder<StringValue>()
                                         .setPossibleValues(StringValue.of("value1"))
                                         .setValueMatchRequired(true)
                                         .setRequired(true)
                                         .build()),
-                        Optional.of(
-                                new TypeProperty.Builder<StringValue>()
-                                        .setProhibited(true)
-                                        .build()));
+                        Optional.of(Property.prohibited()));
 
         assertThat(ACTION_SPEC.convertPropertyToProto(property))
                 .isEqualTo(
@@ -413,10 +410,10 @@
     }
 
     @AutoValue
-    abstract static class Argument {
+    abstract static class Arguments {
 
         static Builder newBuilder() {
-            return new AutoValue_ActionSpecTest_Argument.Builder();
+            return new AutoValue_ActionSpecTest_Arguments.Builder();
         }
 
         abstract EntityValue requiredEntityField();
@@ -432,7 +429,7 @@
         abstract List<String> repeatedStringField();
 
         @AutoValue.Builder
-        abstract static class Builder implements BuilderOf<Argument> {
+        abstract static class Builder implements BuilderOf<Arguments> {
 
             abstract Builder setRequiredEntityField(EntityValue value);
 
@@ -448,22 +445,22 @@
 
             @NonNull
             @Override
-            public abstract Argument build();
+            public abstract Arguments build();
         }
     }
 
     @AutoValue
-    abstract static class Property {
+    abstract static class Properties {
 
-        static Property create(
-                TypeProperty<Entity> requiredEntityField,
-                Optional<TypeProperty<Entity>> optionalEntityField,
-                Optional<TypeProperty<TestEnum>> optionalEnumField,
-                Optional<TypeProperty<Entity>> repeatedEntityField,
-                TypeProperty<StringValue> requiredStringField,
-                Optional<TypeProperty<StringValue>> optionalStringField,
-                Optional<TypeProperty<StringValue>> repeatedStringField) {
-            return new AutoValue_ActionSpecTest_Property(
+        static Properties create(
+                Property<Entity> requiredEntityField,
+                Optional<Property<Entity>> optionalEntityField,
+                Optional<Property<TestEnum>> optionalEnumField,
+                Optional<Property<Entity>> repeatedEntityField,
+                Property<StringValue> requiredStringField,
+                Optional<Property<StringValue>> optionalStringField,
+                Optional<Property<StringValue>> repeatedStringField) {
+            return new AutoValue_ActionSpecTest_Properties(
                     requiredEntityField,
                     optionalEntityField,
                     optionalEnumField,
@@ -473,9 +470,9 @@
                     repeatedStringField);
         }
 
-        static Property create(
-                TypeProperty<Entity> requiredEntityField,
-                TypeProperty<StringValue> requiredStringField) {
+        static Properties create(
+                Property<Entity> requiredEntityField,
+                Property<StringValue> requiredStringField) {
             return create(
                     requiredEntityField,
                     Optional.empty(),
@@ -486,26 +483,26 @@
                     Optional.empty());
         }
 
-        abstract TypeProperty<Entity> requiredEntityField();
+        abstract Property<Entity> requiredEntityField();
 
-        abstract Optional<TypeProperty<Entity>> optionalEntityField();
+        abstract Optional<Property<Entity>> optionalEntityField();
 
-        abstract Optional<TypeProperty<TestEnum>> optionalEnumField();
+        abstract Optional<Property<TestEnum>> optionalEnumField();
 
-        abstract Optional<TypeProperty<Entity>> repeatedEntityField();
+        abstract Optional<Property<Entity>> repeatedEntityField();
 
-        abstract TypeProperty<StringValue> requiredStringField();
+        abstract Property<StringValue> requiredStringField();
 
-        abstract Optional<TypeProperty<StringValue>> optionalStringField();
+        abstract Optional<Property<StringValue>> optionalStringField();
 
-        abstract Optional<TypeProperty<StringValue>> repeatedStringField();
+        abstract Optional<Property<StringValue>> repeatedStringField();
     }
 
     @AutoValue
-    abstract static class GenericEntityArgument {
+    abstract static class GenericEntityArguments {
 
         static Builder newBuilder() {
-            return new AutoValue_ActionSpecTest_GenericEntityArgument.Builder();
+            return new AutoValue_ActionSpecTest_GenericEntityArguments.Builder();
         }
 
         abstract String singularField();
@@ -515,7 +512,7 @@
         abstract List<String> repeatedField();
 
         @AutoValue.Builder
-        abstract static class Builder implements BuilderOf<GenericEntityArgument> {
+        abstract static class Builder implements BuilderOf<GenericEntityArguments> {
 
             abstract Builder setSingularField(String value);
 
@@ -525,7 +522,7 @@
 
             @NonNull
             @Override
-            public abstract GenericEntityArgument build();
+            public abstract GenericEntityArguments build();
         }
     }
 
@@ -533,17 +530,17 @@
     abstract static class GenericEntityProperty {
 
         static GenericEntityProperty create(
-                TypeProperty<String> singularField,
-                Optional<TypeProperty<String>> optionalField,
-                Optional<TypeProperty<String>> repeatedField) {
+                Property<String> singularField,
+                Optional<Property<String>> optionalField,
+                Optional<Property<String>> repeatedField) {
             return new AutoValue_ActionSpecTest_GenericEntityProperty(
                     singularField, optionalField, repeatedField);
         }
 
-        abstract TypeProperty<String> singularField();
+        abstract Property<String> singularField();
 
-        abstract Optional<TypeProperty<String>> optionalField();
+        abstract Optional<Property<String>> optionalField();
 
-        abstract Optional<TypeProperty<String>> repeatedField();
+        abstract Optional<Property<String>> repeatedField();
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/TypePropertyTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/PropertyTest.kt
similarity index 93%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/TypePropertyTest.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/PropertyTest.kt
index c6d5eda..7563a3f 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/TypePropertyTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/PropertyTest.kt
@@ -22,11 +22,11 @@
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class TypePropertyTest {
+class PropertyTest {
     @Test
     fun dynamicInventory_test() {
         val mutablePossibleValues = mutableListOf<String>("a", "b")
-        val testProperty = TypeProperty.Builder<String>()
+        val testProperty = Property.Builder<String>()
             .setPossibleValueSupplier { mutablePossibleValues.toList() }
             .build()
 
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt
index 06c40a2..d403689 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskCapabilityImplTest.kt
@@ -18,12 +18,11 @@
 import android.util.SizeF
 import androidx.appactions.interaction.capabilities.core.AppEntityListener
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.EntitySearchResult
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
+import androidx.appactions.interaction.capabilities.core.ExecutionSessionFactory
 import androidx.appactions.interaction.capabilities.core.HostProperties
-import androidx.appactions.interaction.capabilities.core.InitArg
-import androidx.appactions.interaction.capabilities.core.SessionFactory
+import androidx.appactions.interaction.capabilities.core.SessionContext
 import androidx.appactions.interaction.capabilities.core.ValidationResult
 import androidx.appactions.interaction.capabilities.core.ValueListener
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
@@ -38,23 +37,22 @@
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.testing.spec.Argument
+import androidx.appactions.interaction.capabilities.core.properties.Property
+import androidx.appactions.interaction.capabilities.core.testing.spec.Arguments
 import androidx.appactions.interaction.capabilities.core.testing.spec.CapabilityStructFill
 import androidx.appactions.interaction.capabilities.core.testing.spec.CapabilityTwoEntityValues
 import androidx.appactions.interaction.capabilities.core.testing.spec.Confirmation
+import androidx.appactions.interaction.capabilities.core.testing.spec.ExecutionSession
 import androidx.appactions.interaction.capabilities.core.testing.spec.Output
-import androidx.appactions.interaction.capabilities.core.testing.spec.Property
-import androidx.appactions.interaction.capabilities.core.testing.spec.Session
 import androidx.appactions.interaction.capabilities.core.testing.spec.TestEnum
+import androidx.appactions.interaction.capabilities.core.testing.spec.Properties
 import androidx.appactions.interaction.capabilities.core.values.EntityValue
 import androidx.appactions.interaction.capabilities.core.values.ListItem
 import androidx.appactions.interaction.capabilities.core.values.SearchAction
 import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils.buildRequestArgs
 import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils.buildSearchActionParamValue
 import androidx.appactions.interaction.capabilities.testing.internal.FakeCallbackInternal
-import androidx.appactions.interaction.capabilities.testing.internal.SettableFutureWrapper
-import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.CB_TIMEOUT
+import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.awaitSync
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction
 import androidx.appactions.interaction.proto.AppActionsContext.AppDialogState
 import androidx.appactions.interaction.proto.AppActionsContext.DialogParameter
@@ -78,37 +76,36 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import java.util.concurrent.TimeUnit.MILLISECONDS
 import java.util.concurrent.atomic.AtomicInteger
 import java.util.concurrent.atomic.AtomicReference
 import java.util.function.Supplier
 
 @RunWith(JUnit4::class)
 class TaskCapabilityImplTest {
-    val capability: Capability =
+    private val capability: Capability =
         createCapability<EmptyTaskUpdater>(
             SINGLE_REQUIRED_FIELD_PROPERTY,
             sessionFactory =
             {
-                object : Session {
-                    override fun onFinishAsync(argument: Argument) =
-                        Futures.immediateFuture(ExecutionResult.getDefaultInstance<Output>())
+                object : ExecutionSession {
+                    override fun onExecuteAsync(arguments: Arguments) =
+                        Futures.immediateFuture(ExecutionResult.Builder<Output>().build())
                 }
             },
             sessionBridge = { TaskHandler.Builder<Confirmation>().build() },
             sessionUpdaterSupplier = ::EmptyTaskUpdater,
         )
-    val hostProperties: HostProperties =
+    private val hostProperties: HostProperties =
         HostProperties.Builder()
             .setMaxHostSizeDp(
                 SizeF(300f, 500f),
             )
             .build()
-    val fakeSessionId = "fakeSessionId"
+    private val fakeSessionId = "fakeSessionId"
 
     @Test
     fun getAppAction_smokeTest() {
-        assertThat(capability.getAppAction())
+        assertThat(capability.appAction)
             .isEqualTo(
                 AppAction.newBuilder()
                     .setName("actions.intent.TEST")
@@ -125,7 +122,7 @@
 
     @Test
     fun capabilitySession_getUiHandle() {
-        val externalSession = object : Session {}
+        val externalSession = object : ExecutionSession {}
         val capability =
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
@@ -139,20 +136,20 @@
 
     @Test
     @kotlin.Throws(Exception::class)
-    fun onInitInvoked_invokedOnce() {
-        val onInitInvocationCount = AtomicInteger(0)
+    fun onCreateInvoked_invokedOnce() {
+        val onCreateInvocationCount = AtomicInteger(0)
         val capability: Capability =
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory =
-                SessionFactory {
-                    object : Session {
-                        override fun onInit(initArg: InitArg) {
-                            onInitInvocationCount.incrementAndGet()
+                ExecutionSessionFactory {
+                    object : ExecutionSession {
+                        override fun onCreate(sessionContext: SessionContext) {
+                            onCreateInvocationCount.incrementAndGet()
                         }
-                        override fun onFinishAsync(argument: Argument) =
+                        override fun onExecuteAsync(arguments: Arguments) =
                             Futures.immediateFuture(
-                                ExecutionResult.getDefaultInstance<Output>(),
+                                ExecutionResult.Builder<Output>().build(),
                             )
                     }
                 },
@@ -168,7 +165,7 @@
             callback,
         )
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onInitInvocationCount.get()).isEqualTo(1)
+        assertThat(onCreateInvocationCount.get()).isEqualTo(1)
 
         // TURN 2.
         val callback2 = FakeCallbackInternal()
@@ -181,7 +178,7 @@
             callback2,
         )
         assertThat(callback2.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onInitInvocationCount.get()).isEqualTo(1)
+        assertThat(onCreateInvocationCount.get()).isEqualTo(1)
     }
 
     class RequiredTaskUpdater : AbstractTaskUpdater() {
@@ -214,9 +211,7 @@
                     mCompleterRef.getAndSet(
                         newCompleter,
                     )
-                if (oldCompleter != null) {
-                    oldCompleter.setCancelled()
-                }
+                oldCompleter?.setCancelled()
                 "waiting for setValidationResult"
             }
         }
@@ -224,17 +219,17 @@
 
     @Test
     fun duringExecution_uiHandleRegistered(): Unit = runBlocking {
-        val onFinishReached = CompletableDeferred<Unit>()
-        val onFinishResult = CompletableDeferred<ExecutionResult<Output>>()
-        val externalSession = object : Session {
-            override suspend fun onFinish(argument: Argument): ExecutionResult<Output> {
-                onFinishReached.complete(Unit)
-                return onFinishResult.await()
+        val onExecuteReached = CompletableDeferred<Unit>()
+        val onExecuteResult = CompletableDeferred<ExecutionResult<Output>>()
+        val externalSession = object : ExecutionSession {
+            override suspend fun onExecute(arguments: Arguments): ExecutionResult<Output> {
+                onExecuteReached.complete(Unit)
+                return onExecuteResult.await()
             }
         }
         val capability: Capability = createCapability(
             SINGLE_REQUIRED_FIELD_PROPERTY,
-            sessionFactory = SessionFactory { externalSession },
+            sessionFactory = ExecutionSessionFactory { externalSession },
             sessionBridge = SessionBridge { TaskHandler.Builder<Confirmation>().build() },
             sessionUpdaterSupplier = ::RequiredTaskUpdater,
         )
@@ -248,12 +243,12 @@
             ),
             callback,
         )
-        onFinishReached.await()
+        onExecuteReached.await()
         assertThat(UiHandleRegistry.getSessionIdFromUiHandle(externalSession)).isEqualTo(
             "mySessionId",
         )
 
-        onFinishResult.complete(ExecutionResult.getDefaultInstance<Output>())
+        onExecuteResult.complete(ExecutionResult.Builder<Output>().build())
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
         assertThat(UiHandleRegistry.getSessionIdFromUiHandle(externalSession)).isNull()
     }
@@ -265,11 +260,11 @@
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory =
-                SessionFactory {
-                    object : Session {
-                        override fun onFinishAsync(argument: Argument) =
+                ExecutionSessionFactory {
+                    object : ExecutionSession {
+                        override fun onExecuteAsync(arguments: Arguments) =
                             Futures.immediateFuture(
-                                ExecutionResult.getDefaultInstance<Output>(),
+                                ExecutionResult.Builder<Output>().build(),
                             )
                     }
                 },
@@ -278,7 +273,7 @@
             )
         val session = capability.createSession(fakeSessionId, hostProperties)
 
-        assertThat(capability.getAppAction())
+        assertThat(capability.appAction)
             .isEqualTo(
                 AppAction.newBuilder()
                     .setName("actions.intent.TEST")
@@ -301,17 +296,17 @@
 
     @Test
     fun slotFilling_getStatus_smokeTest() {
-        val property: CapabilityTwoEntityValues.Property =
-            CapabilityTwoEntityValues.Property.newBuilder()
+        val property: CapabilityTwoEntityValues.Properties =
+            CapabilityTwoEntityValues.Properties.newBuilder()
                 .setSlotA(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setSlotB(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
@@ -319,15 +314,15 @@
                 )
                 .build()
         val sessionFactory =
-            SessionFactory<CapabilityTwoEntityValues.Session> {
-                object : CapabilityTwoEntityValues.Session {
-                    override suspend fun onFinish(
-                        argument: CapabilityTwoEntityValues.Argument,
-                    ): ExecutionResult<Void> = ExecutionResult.getDefaultInstance()
+            ExecutionSessionFactory<CapabilityTwoEntityValues.ExecutionSession> {
+                object : CapabilityTwoEntityValues.ExecutionSession {
+                    override suspend fun onExecute(
+                        arguments: CapabilityTwoEntityValues.Arguments,
+                    ): ExecutionResult<Void> = ExecutionResult.Builder<Void>().build()
                 }
             }
         val sessionBridge =
-            SessionBridge<CapabilityTwoEntityValues.Session, Void> {
+            SessionBridge<CapabilityTwoEntityValues.ExecutionSession, Void> {
                 TaskHandler.Builder<Void>()
                     .registerValueTaskParam(
                         "slotA",
@@ -395,18 +390,18 @@
     @Test
     @kotlin.Throws(Exception::class)
     fun slotFilling_optionalButRejectedParam_onFinishNotInvoked() {
-        val onFinishInvocationCount = AtomicInteger(0)
-        val property: CapabilityTwoEntityValues.Property =
-            CapabilityTwoEntityValues.Property.newBuilder()
+        val onExecuteInvocationCount = AtomicInteger(0)
+        val property: CapabilityTwoEntityValues.Properties =
+            CapabilityTwoEntityValues.Properties.newBuilder()
                 .setSlotA(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setSlotB(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(false)
@@ -414,18 +409,18 @@
                 )
                 .build()
         val sessionFactory =
-            SessionFactory<CapabilityTwoEntityValues.Session> {
-                object : CapabilityTwoEntityValues.Session {
-                    override suspend fun onFinish(
-                        argument: CapabilityTwoEntityValues.Argument,
+            ExecutionSessionFactory<CapabilityTwoEntityValues.ExecutionSession> {
+                object : CapabilityTwoEntityValues.ExecutionSession {
+                    override suspend fun onExecute(
+                        arguments: CapabilityTwoEntityValues.Arguments,
                     ): ExecutionResult<Void> {
-                        onFinishInvocationCount.incrementAndGet()
-                        return ExecutionResult.getDefaultInstance()
+                        onExecuteInvocationCount.incrementAndGet()
+                        return ExecutionResult.Builder<Void>().build()
                     }
                 }
             }
         val sessionBridge =
-            SessionBridge<CapabilityTwoEntityValues.Session, Void> {
+            SessionBridge<CapabilityTwoEntityValues.ExecutionSession, Void> {
                 TaskHandler.Builder<Void>()
                     .registerValueTaskParam(
                         "slotA",
@@ -463,7 +458,7 @@
             callback,
         )
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onFinishInvocationCount.get()).isEqualTo(0)
+        assertThat(onExecuteInvocationCount.get()).isEqualTo(0)
         assertThat(getCurrentValues("slotA", session.state))
             .containsExactly(
                 CurrentValue.newBuilder()
@@ -487,17 +482,17 @@
     @Test
     @kotlin.Throws(Exception::class)
     fun slotFilling_assistantRemovedParam_clearInSdkState() {
-        val property: Property =
-            Property.newBuilder()
+        val property: Properties =
+            Properties.newBuilder()
                 .setRequiredEntityField(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setEnumField(
-                    TypeProperty.Builder<TestEnum>()
+                    Property.Builder<TestEnum>()
                         .setPossibleValues(TestEnum.VALUE_1, TestEnum.VALUE_2)
                         .setRequired(true)
                         .build(),
@@ -506,7 +501,7 @@
         val capability: Capability =
             createCapability(
                 property,
-                sessionFactory = SessionFactory { Session.DEFAULT },
+                sessionFactory = ExecutionSessionFactory { ExecutionSession.DEFAULT },
                 sessionBridge = SessionBridge { TaskHandler.Builder<Confirmation>().build() },
                 sessionUpdaterSupplier = ::EmptyTaskUpdater,
             )
@@ -565,9 +560,9 @@
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory = {
-                    object : Session {
-                        override suspend fun onFinish(argument: Argument) =
-                            ExecutionResult.getDefaultInstance<Output>()
+                    object : ExecutionSession {
+                        override suspend fun onExecute(arguments: Arguments) =
+                            ExecutionResult.Builder<Output>().build()
 
                         override fun getRequiredEntityListener() =
                             object : AppEntityListener<EntityValue> {
@@ -592,7 +587,7 @@
                     }
                 },
                 sessionBridge =
-                SessionBridge<Session, Confirmation> { session ->
+                SessionBridge<ExecutionSession, Confirmation> { session ->
                     val builder = TaskHandler.Builder<Confirmation>()
                     session.getRequiredEntityListener()
                         ?.let { listener: AppEntityListener<EntityValue> ->
@@ -702,29 +697,29 @@
     @Test
     @kotlin.Throws(Exception::class)
     @Suppress("DEPRECATION") // TODO(b/269638788) migrate session state to AppDialogState message
-    fun identifierOnly_refillsStruct() {
-        val property: CapabilityStructFill.Property =
-            CapabilityStructFill.Property.newBuilder()
-                .setListItem(TypeProperty.Builder<ListItem>().setRequired(true).build())
-                .setAnyString(TypeProperty.Builder<StringValue>().setRequired(true).build())
+    fun identifierOnly_refillsStruct() = runBlocking<Unit> {
+        val property: CapabilityStructFill.Properties =
+            CapabilityStructFill.Properties.newBuilder()
+                .setListItem(Property.Builder<ListItem>().setRequired(true).build())
+                .setAnyString(Property.Builder<StringValue>().setRequired(true).build())
                 .build()
         val item1: ListItem = ListItem.newBuilder().setName("red apple").setId("item1").build()
         val item2: ListItem = ListItem.newBuilder().setName("green apple").setId("item2").build()
-        val onReceivedCb: SettableFutureWrapper<ListItem> = SettableFutureWrapper()
-        val onFinishListItemCb: SettableFutureWrapper<ListItem> = SettableFutureWrapper()
-        val onFinishStringCb: SettableFutureWrapper<String> = SettableFutureWrapper()
+        val onReceivedDeferred = CompletableDeferred<ListItem>()
+        val onExecuteListItemDeferred = CompletableDeferred<ListItem>()
+        val onExecuteStringDeferred = CompletableDeferred<String>()
 
         val sessionFactory =
-            SessionFactory<CapabilityStructFill.Session> {
-                object : CapabilityStructFill.Session {
-                    override suspend fun onFinish(
-                        argument: CapabilityStructFill.Argument,
+            ExecutionSessionFactory<CapabilityStructFill.ExecutionSession> {
+                object : CapabilityStructFill.ExecutionSession {
+                    override suspend fun onExecute(
+                        arguments: CapabilityStructFill.Arguments,
                     ): ExecutionResult<Void> {
-                        val listItem: ListItem = argument.listItem().orElse(null)
-                        val string: String = argument.anyString().orElse(null)
-                        onFinishListItemCb.set(listItem)
-                        onFinishStringCb.set(string)
-                        return ExecutionResult.getDefaultInstance<Void>()
+                        val listItem: ListItem = arguments.listItem().orElse(null)
+                        val string: String = arguments.anyString().orElse(null)
+                        onExecuteListItemDeferred.complete(listItem)
+                        onExecuteStringDeferred.complete(string)
+                        return ExecutionResult.Builder<Void>().build()
                     }
 
                     override fun getListItemListener() =
@@ -732,7 +727,7 @@
                             override fun onReceivedAsync(
                                 value: ListItem,
                             ): ListenableFuture<ValidationResult> {
-                                onReceivedCb.set(value)
+                                onReceivedDeferred.complete(value)
                                 return Futures.immediateFuture(ValidationResult.newAccepted())
                             }
 
@@ -749,7 +744,7 @@
                 }
             }
         val sessionBridge =
-            SessionBridge<CapabilityStructFill.Session, Void> { session ->
+            SessionBridge<CapabilityStructFill.ExecutionSession, Void> { session ->
                 TaskHandler.Builder<Void>()
                     .registerAppEntityTaskParam(
                         "listItem",
@@ -779,8 +774,8 @@
             callback,
         )
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onReceivedCb.getFuture().isDone()).isFalse()
-        assertThat(onFinishListItemCb.getFuture().isDone()).isFalse()
+        assertThat(onReceivedDeferred.isCompleted).isFalse()
+        assertThat(onExecuteListItemDeferred.isCompleted).isFalse()
         assertThat(session.state)
             .isEqualTo(
                 AppDialogState.newBuilder()
@@ -827,8 +822,8 @@
             callback2,
         )
         assertThat(callback2.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onReceivedCb.getFuture().get(CB_TIMEOUT, MILLISECONDS)).isEqualTo(item2)
-        assertThat(onFinishListItemCb.getFuture().isDone()).isFalse()
+        assertThat(onReceivedDeferred.awaitSync()).isEqualTo(item2)
+        assertThat(onExecuteListItemDeferred.isCompleted).isFalse()
 
         // third sync request, sending grounded ParamValue with identifier only, completes task
         val callback3 = FakeCallbackInternal()
@@ -843,23 +838,17 @@
             callback3,
         )
         assertThat(callback3.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onFinishListItemCb.getFuture().get(CB_TIMEOUT, MILLISECONDS))
-            .isEqualTo(
-                item2,
-            )
-        assertThat(
-            onFinishStringCb.getFuture().get(CB_TIMEOUT, MILLISECONDS),
-        )
-            .isEqualTo("unused")
+        assertThat(onExecuteListItemDeferred.awaitSync()).isEqualTo(item2)
+        assertThat(onExecuteStringDeferred.awaitSync()).isEqualTo("unused")
     }
 
     @Test
     @kotlin.Throws(Exception::class)
     fun executionResult_resultReturned() {
         val sessionFactory =
-            SessionFactory<Session> {
-                object : Session {
-                    override suspend fun onFinish(argument: Argument) =
+            ExecutionSessionFactory<ExecutionSession> {
+                object : ExecutionSession {
+                    override suspend fun onExecute(arguments: Arguments) =
                         ExecutionResult.Builder<Output>()
                             .setOutput(
                                 Output.builder()
@@ -873,7 +862,7 @@
                 }
             }
         val capability =
-            CapabilityBuilder().setId("fakeId").setSessionFactory(sessionFactory).build()
+            CapabilityBuilder().setId("fakeId").setExecutionSessionFactory(sessionFactory).build()
         val session = capability.createSession(fakeSessionId, hostProperties)
         val callback = FakeCallbackInternal()
         val expectedOutput: StructuredOutput =
@@ -915,35 +904,60 @@
             .containsExactlyElementsIn(expectedOutput.getOutputValuesList())
     }
 
+    @Test
+    @kotlin.Throws(Exception::class)
+    fun executionResult_shouldStartDictation_resultReturned() {
+        val sessionFactory =
+            ExecutionSessionFactory<ExecutionSession> {
+                object : ExecutionSession {
+                    override suspend fun onExecute(arguments: Arguments) =
+                        ExecutionResult.Builder<Output>()
+                            .setStartDictation(true)
+                            .build()
+                }
+            }
+        val capability =
+            CapabilityBuilder().setId("fakeId").setExecutionSessionFactory(sessionFactory).build()
+        val session = capability.createSession(fakeSessionId, hostProperties)
+        val callback = FakeCallbackInternal()
+
+        session.execute(
+            buildRequestArgs(
+                SYNC, /* args...= */
+                "required",
+                ParamValue.newBuilder().setIdentifier("foo").setStringValue("foo").build(),
+            ),
+            callback,
+        )
+
+        assertThat(callback.receiveResponse().fulfillmentResponse!!.startDictation).isTrue()
+    }
+
     /**
-     * an implementation of CapabilityBuilderBase using Argument. Output, etc. defined under
+     * an implementation of Capability.Builder using Argument. Output, etc. defined under
      * testing/spec
      */
     class CapabilityBuilder :
-        CapabilityBuilderBase<
+        Capability.Builder<
             CapabilityBuilder,
-            Property,
-            Argument,
+            Properties,
+            Arguments,
             Output,
             Confirmation,
-            RequiredTaskUpdater,
-            Session,
+            ExecutionSession,
             >(ACTION_SPEC) {
 
         init {
             setProperty(SINGLE_REQUIRED_FIELD_PROPERTY)
         }
 
-        override val sessionBridge: SessionBridge<Session, Confirmation> = SessionBridge {
+        override val sessionBridge: SessionBridge<ExecutionSession, Confirmation> = SessionBridge {
             TaskHandler.Builder<Confirmation>().build()
         }
-        override val sessionUpdaterSupplier: Supplier<RequiredTaskUpdater> = Supplier {
-            RequiredTaskUpdater()
-        }
 
-        public override fun setSessionFactory(
-            sessionFactory: SessionFactory<Session>,
-        ): CapabilityBuilder = super.setSessionFactory(sessionFactory)
+        public override fun setExecutionSessionFactory(
+            sessionFactory: ExecutionSessionFactory<ExecutionSession>,
+        ): CapabilityBuilder = super.setExecutionSessionFactory(sessionFactory)
     }
 
     companion object {
@@ -1000,38 +1014,38 @@
                     return ParamValue.newBuilder().build()
                 }
             }
-        private val ACTION_SPEC: ActionSpec<Property, Argument, Output> =
+        private val ACTION_SPEC: ActionSpec<Properties, Arguments, Output> =
             ActionSpecBuilder.ofCapabilityNamed(
                 CAPABILITY_NAME,
             )
-                .setDescriptor(Property::class.java)
-                .setArgument(Argument::class.java, Argument::newBuilder)
+                .setDescriptor(Properties::class.java)
+                .setArguments(Arguments::class.java, Arguments::newBuilder)
                 .setOutput(Output::class.java)
                 .bindParameter(
                     "required",
-                    Property::requiredEntityField,
-                    Argument.Builder::setRequiredEntityField,
+                    Properties::requiredEntityField,
+                    Arguments.Builder::setRequiredEntityField,
                     TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                     TypeConverters.ENTITY_ENTITY_CONVERTER,
                 )
                 .bindOptionalParameter(
                     "optional",
-                    Property::optionalStringField,
-                    Argument.Builder::setOptionalStringField,
+                    Properties::optionalStringField,
+                    Arguments.Builder::setOptionalStringField,
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
                 )
                 .bindOptionalParameter(
                     "optionalEnum",
-                    Property::enumField,
-                    Argument.Builder::setEnumField,
+                    Properties::enumField,
+                    Arguments.Builder::setEnumField,
                     ENUM_CONVERTER,
                     { Entity.newBuilder().setIdentifier(it.toString()).build() },
                 )
                 .bindRepeatedParameter(
                     "repeated",
-                    Property::repeatedStringField,
-                    Argument.Builder::setRepeatedStringField,
+                    Properties::repeatedStringField,
+                    Arguments.Builder::setRepeatedStringField,
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
                 )
@@ -1047,10 +1061,10 @@
                 )
                 .build()
 
-        private val SINGLE_REQUIRED_FIELD_PROPERTY: Property =
-            Property.newBuilder()
+        private val SINGLE_REQUIRED_FIELD_PROPERTY: Properties =
+            Properties.newBuilder()
                 .setRequiredEntityField(
-                    TypeProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
@@ -1076,15 +1090,15 @@
          * etc., defined under ../../testing/spec
          */
         private fun <SessionUpdaterT : AbstractTaskUpdater> createCapability(
-            property: Property,
-            sessionFactory: SessionFactory<Session>,
-            sessionBridge: SessionBridge<Session, Confirmation>,
+            property: Properties,
+            sessionFactory: ExecutionSessionFactory<ExecutionSession>,
+            sessionBridge: SessionBridge<ExecutionSession, Confirmation>,
             sessionUpdaterSupplier: Supplier<SessionUpdaterT>,
         ): TaskCapabilityImpl<
-            Property,
-            Argument,
+            Properties,
+            Arguments,
             Output,
-            Session,
+            ExecutionSession,
             Confirmation,
             SessionUpdaterT,
             > {
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt
index b4fa8ab..d8d9872 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/task/impl/TaskSlotProcessorTest.kt
@@ -24,7 +24,7 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.values.SearchAction
 import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils
-import androidx.appactions.interaction.capabilities.testing.internal.SettableFutureWrapper
+import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.awaitSync
 import androidx.appactions.interaction.proto.CurrentValue
 import androidx.appactions.interaction.proto.DisambiguationData
 import androidx.appactions.interaction.proto.Entity
@@ -33,6 +33,7 @@
 import androidx.appactions.interaction.protobuf.Value
 import com.google.common.truth.Truth.assertThat
 import com.google.common.util.concurrent.ListenableFuture
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -182,14 +183,14 @@
     @Test
     @Throws(Exception::class)
     fun processSlot_repeatedValue_accepted(): Unit = runBlocking {
-        val lastReceivedArgs = SettableFutureWrapper<List<String?>>()
+        val lastReceivedArgs = CompletableDeferred<List<String>>()
         val binding =
             TaskParamBinding(
                 "repeatedValue",
                 { false },
                 createValueListResolver(
                     ValidationResult.newAccepted(),
-                ) { lastReceivedArgs.set(it) },
+                ) { lastReceivedArgs.complete(it) },
                 TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                 null,
                 null,
@@ -219,7 +220,7 @@
                     .setStatus(CurrentValue.Status.ACCEPTED)
                     .build(),
             )
-        assertThat(lastReceivedArgs.getFuture().get()).isEqualTo(
+        assertThat(lastReceivedArgs.awaitSync()).isEqualTo(
             listOf(
                 "testValue1",
                 "testValue2",
@@ -230,14 +231,14 @@
     @Test
     @Throws(Exception::class)
     fun processSlot_repeatedValue_rejected(): Unit = runBlocking {
-        val lastReceivedArgs = SettableFutureWrapper<List<String>>()
+        val lastReceivedArgs = CompletableDeferred<List<String>>()
         val binding =
             TaskParamBinding(
                 "repeatedValue",
                 { false },
                 createValueListResolver(
                     ValidationResult.newRejected(),
-                ) { lastReceivedArgs.set(it) },
+                ) { lastReceivedArgs.complete(it) },
                 TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                 null,
                 null,
@@ -267,7 +268,7 @@
                     .setStatus(CurrentValue.Status.REJECTED)
                     .build(),
             )
-        assertThat(lastReceivedArgs.getFuture().get()).isEqualTo(
+        assertThat(lastReceivedArgs.awaitSync()).isEqualTo(
             listOf(
                 "testValue1",
                 "testValue2",
@@ -279,17 +280,17 @@
     @Throws(Exception::class)
     fun listValues_oneAccepted_oneAssistantDisambig_invokesRendererAndOnReceived(): Unit =
         runBlocking {
-            val onReceivedCb = SettableFutureWrapper<String>()
-            val renderCb = SettableFutureWrapper<List<String?>>()
+            val onReceivedDeferred = CompletableDeferred<String>()
+            val renderDeferred = CompletableDeferred<List<String>>()
             val binding =
                 TaskParamBinding(
                     "assistantDrivenSlot",
                     { !it.hasIdentifier() },
                     createAssistantDisambigResolver(
                         ValidationResult.newAccepted(),
-                        { onReceivedCb.set(it) },
+                        { onReceivedDeferred.complete(it) },
                     ) {
-                        renderCb.set(it)
+                        renderDeferred.complete(it)
                     },
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     null,
@@ -327,8 +328,8 @@
             val (isSuccessful, processedValues) =
                 TaskSlotProcessor.processSlot("assistantDrivenSlot", values, taskParamMap)
             assertThat(isSuccessful).isFalse()
-            assertThat(onReceivedCb.getFuture().get()).isEqualTo("id")
-            assertThat(renderCb.getFuture().get()).isEqualTo(listOf("entity-1", "entity-2"))
+            assertThat(onReceivedDeferred.awaitSync()).isEqualTo("id")
+            assertThat(renderDeferred.awaitSync()).isEqualTo(listOf("entity-1", "entity-2"))
             assertThat(processedValues)
                 .containsExactly(
                     previouslyAccepted,
@@ -346,16 +347,16 @@
     @Test
     @Throws(Exception::class)
     fun singularValue_appDisambigRejected_onReceivedNotCalled(): Unit = runBlocking {
-        val onReceivedCb = SettableFutureWrapper<String>()
-        val appSearchCb = SettableFutureWrapper<SearchAction<String>>()
+        val onReceivedDeferred = CompletableDeferred<String>()
+        val appSearchDeferred = CompletableDeferred<SearchAction<String>>()
         val entitySearchResult = EntitySearchResult.Builder<String>().build()
         val resolver =
             createAppEntityListener(
                 ValidationResult.newAccepted(),
-                { result: String -> onReceivedCb.set(result) },
+                { result: String -> onReceivedDeferred.complete(result) },
                 entitySearchResult,
             ) { result: SearchAction<String> ->
-                appSearchCb.set(result)
+                appSearchDeferred.complete(result)
             }
         val binding =
             TaskParamBinding(
@@ -380,9 +381,9 @@
             TaskSlotProcessor.processSlot("appDrivenSlot", values, taskParamMap)
         assertThat(isSuccessful).isFalse()
 
-        assertThat(onReceivedCb.getFuture().isDone).isFalse()
-        assertThat(appSearchCb.getFuture().isDone).isTrue()
-        assertThat(appSearchCb.getFuture().get())
+        assertThat(onReceivedDeferred.isCompleted).isFalse()
+        assertThat(appSearchDeferred.isCompleted).isTrue()
+        assertThat(appSearchDeferred.awaitSync())
             .isEqualTo(SearchAction.newBuilder<String>().setQuery("A").setObject("nested").build())
         assertThat(processedValues)
             .containsExactly(
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Argument.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Arguments.java
similarity index 92%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Argument.java
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Arguments.java
index 4e625f2..469c5a2 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Argument.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Arguments.java
@@ -27,10 +27,10 @@
 
 /** Testing implementation of a capability Argument. */
 @AutoValue
-public abstract class Argument {
+public abstract class Arguments {
 
     public static Builder newBuilder() {
-        return new AutoValue_Argument.Builder();
+        return new AutoValue_Arguments.Builder();
     }
 
     public abstract Optional<EntityValue> requiredEntityField();
@@ -43,7 +43,7 @@
 
     /** Builder for the testing Argument. */
     @AutoValue.Builder
-    public abstract static class Builder implements BuilderOf<Argument> {
+    public abstract static class Builder implements BuilderOf<Arguments> {
 
         public abstract Builder setRequiredEntityField(EntityValue value);
 
@@ -55,6 +55,6 @@
 
         @NonNull
         @Override
-        public abstract Argument build();
+        public abstract Arguments build();
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.java
index 6c665ac..1b8a88e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityStructFill.java
@@ -20,15 +20,15 @@
 
 import androidx.annotation.NonNull;
 import androidx.appactions.interaction.capabilities.core.AppEntityListener;
-import androidx.appactions.interaction.capabilities.core.BaseSession;
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession;
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
 import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter;
 import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter;
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
 import androidx.appactions.interaction.capabilities.core.values.ListItem;
 
 import com.google.auto.value.AutoValue;
@@ -39,20 +39,20 @@
 public final class CapabilityStructFill {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Argument, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
-                    .setArgument(Argument.class, Argument::newBuilder)
+                    .setDescriptor(Properties.class)
+                    .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "listItem",
-                            Property::listItem,
-                            Argument.Builder::setListItem,
+                            Properties::listItem,
+                            Arguments.Builder::setListItem,
                             ParamValueConverter.Companion.of(LIST_ITEM_TYPE_SPEC),
                             EntityConverter.Companion.of(LIST_ITEM_TYPE_SPEC)::convert)
                     .bindOptionalParameter(
                             "string",
-                            Property::anyString,
-                            Argument.Builder::setAnyString,
+                            Properties::anyString,
+                            Arguments.Builder::setAnyString,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .build();
@@ -61,18 +61,18 @@
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Argument {
+    public abstract static class Arguments {
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityStructFill_Argument.Builder();
+            return new AutoValue_CapabilityStructFill_Arguments.Builder();
         }
 
         public abstract Optional<ListItem> listItem();
 
         public abstract Optional<String> anyString();
 
-        /** Builder for the testing Argument. */
+        /** Builder for the testing Arguments. */
         @AutoValue.Builder
-        public abstract static class Builder implements BuilderOf<Argument> {
+        public abstract static class Builder implements BuilderOf<Arguments> {
 
             public abstract Builder setListItem(@NonNull ListItem value);
 
@@ -80,38 +80,38 @@
 
             @NonNull
             @Override
-            public abstract Argument build();
+            public abstract Arguments build();
         }
     }
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Property {
+    public abstract static class Properties {
         @NonNull
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityStructFill_Property.Builder();
+            return new AutoValue_CapabilityStructFill_Properties.Builder();
         }
 
-        public abstract Optional<TypeProperty<ListItem>> listItem();
+        public abstract Optional<Property<ListItem>> listItem();
 
-        public abstract Optional<TypeProperty<StringValue>> anyString();
+        public abstract Optional<Property<StringValue>> anyString();
 
         /** Builder for {@link Property} */
         @AutoValue.Builder
         public abstract static class Builder {
 
             @NonNull
-            public abstract Builder setListItem(@NonNull TypeProperty<ListItem> value);
+            public abstract Builder setListItem(@NonNull Property<ListItem> value);
 
             @NonNull
-            public abstract Builder setAnyString(@NonNull TypeProperty<StringValue> value);
+            public abstract Builder setAnyString(@NonNull Property<StringValue> value);
 
             @NonNull
-            public abstract Property build();
+            public abstract Properties build();
         }
     }
 
-    public interface Session extends BaseSession<Argument, Void> {
+    public interface ExecutionSession extends BaseExecutionSession<Arguments, Void> {
         @NonNull
         AppEntityListener<ListItem> getListItemListener();
     }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoEntityValues.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoEntityValues.java
index eaea65a..2a4bc3e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoEntityValues.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoEntityValues.java
@@ -17,13 +17,13 @@
 package androidx.appactions.interaction.capabilities.core.testing.spec;
 
 import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.BaseSession;
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession;
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder;
 import androidx.appactions.interaction.capabilities.core.properties.Entity;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.values.EntityValue;
 
 import com.google.auto.value.AutoValue;
@@ -33,20 +33,20 @@
 public final class CapabilityTwoEntityValues {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Argument, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
-                    .setArgument(Argument.class, Argument::newBuilder)
+                    .setDescriptor(Properties.class)
+                    .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "slotA",
-                            Property::slotA,
-                            Argument.Builder::setSlotA,
+                            Properties::slotA,
+                            Arguments.Builder::setSlotA,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "slotB",
-                            Property::slotB,
-                            Argument.Builder::setSlotB,
+                            Properties::slotB,
+                            Arguments.Builder::setSlotB,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .build();
@@ -55,54 +55,54 @@
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Argument {
+    public abstract static class Arguments {
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityTwoEntityValues_Argument.Builder();
+            return new AutoValue_CapabilityTwoEntityValues_Arguments.Builder();
         }
 
         public abstract Optional<EntityValue> slotA();
 
         public abstract Optional<EntityValue> slotB();
 
-        /** Builder for the testing Argument. */
+        /** Builder for the testing Arguments. */
         @AutoValue.Builder
-        public abstract static class Builder implements BuilderOf<Argument> {
+        public abstract static class Builder implements BuilderOf<Arguments> {
 
             public abstract Builder setSlotA(EntityValue value);
 
             public abstract Builder setSlotB(EntityValue value);
 
             @Override
-            public abstract Argument build();
+            public abstract Arguments build();
         }
     }
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Property {
+    public abstract static class Properties {
         @NonNull
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityTwoEntityValues_Property.Builder();
+            return new AutoValue_CapabilityTwoEntityValues_Properties.Builder();
         }
 
-        public abstract Optional<TypeProperty<Entity>> slotA();
+        public abstract Optional<Property<Entity>> slotA();
 
-        public abstract Optional<TypeProperty<Entity>> slotB();
+        public abstract Optional<Property<Entity>> slotB();
 
         /** Builder for {@link Property} */
         @AutoValue.Builder
         public abstract static class Builder {
 
             @NonNull
-            public abstract Builder setSlotA(@NonNull TypeProperty<Entity> value);
+            public abstract Builder setSlotA(@NonNull Property<Entity> value);
 
             @NonNull
-            public abstract Builder setSlotB(@NonNull TypeProperty<Entity> value);
+            public abstract Builder setSlotB(@NonNull Property<Entity> value);
 
             @NonNull
-            public abstract Property build();
+            public abstract Properties build();
         }
     }
 
-    public interface Session extends BaseSession<Argument, Void> {}
+    public interface ExecutionSession extends BaseExecutionSession<Arguments, Void> {}
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.java
index ded4f5a..20f692d 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/CapabilityTwoStrings.java
@@ -21,8 +21,8 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpec;
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
 
 import com.google.auto.value.AutoValue;
 
@@ -31,20 +31,20 @@
 public final class CapabilityTwoStrings {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Argument, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
-                    .setArgument(Argument.class, Argument::newBuilder)
+                    .setDescriptor(Properties.class)
+                    .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "stringSlotA",
-                            Property::stringSlotA,
-                            Argument.Builder::setStringSlotA,
+                            Properties::stringSlotA,
+                            Arguments.Builder::setStringSlotA,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "stringSlotB",
-                            Property::stringSlotB,
-                            Argument.Builder::setStringSlotB,
+                            Properties::stringSlotB,
+                            Arguments.Builder::setStringSlotB,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .build();
@@ -54,18 +54,18 @@
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Argument {
+    public abstract static class Arguments {
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityTwoStrings_Argument.Builder();
+            return new AutoValue_CapabilityTwoStrings_Arguments.Builder();
         }
 
         public abstract Optional<String> stringSlotA();
 
         public abstract Optional<String> stringSlotB();
 
-        /** Builder for the testing Argument. */
+        /** Builder for the testing Arguments. */
         @AutoValue.Builder
-        public abstract static class Builder implements BuilderOf<Argument> {
+        public abstract static class Builder implements BuilderOf<Arguments> {
 
             public abstract Builder setStringSlotA(@NonNull String value);
 
@@ -73,34 +73,34 @@
 
             @NonNull
             @Override
-            public abstract Argument build();
+            public abstract Arguments build();
         }
     }
 
     /** Two required strings */
     @AutoValue
-    public abstract static class Property {
+    public abstract static class Properties {
         @NonNull
         public static Builder newBuilder() {
-            return new AutoValue_CapabilityTwoStrings_Property.Builder();
+            return new AutoValue_CapabilityTwoStrings_Properties.Builder();
         }
 
-        public abstract Optional<TypeProperty<StringValue>> stringSlotA();
+        public abstract Optional<Property<StringValue>> stringSlotA();
 
-        public abstract Optional<TypeProperty<StringValue>> stringSlotB();
+        public abstract Optional<Property<StringValue>> stringSlotB();
 
         /** Builder for {@link Property} */
         @AutoValue.Builder
         public abstract static class Builder {
 
             @NonNull
-            public abstract Builder setStringSlotA(@NonNull TypeProperty<StringValue> value);
+            public abstract Builder setStringSlotA(@NonNull Property<StringValue> value);
 
             @NonNull
-            public abstract Builder setStringSlotB(@NonNull TypeProperty<StringValue> value);
+            public abstract Builder setStringSlotB(@NonNull Property<StringValue> value);
 
             @NonNull
-            public abstract Property build();
+            public abstract Properties build();
         }
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Session.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/ExecutionSession.kt
similarity index 78%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Session.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/ExecutionSession.kt
index a48dc61..dbe44b3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Session.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/ExecutionSession.kt
@@ -17,21 +17,21 @@
 package androidx.appactions.interaction.capabilities.core.testing.spec
 
 import androidx.appactions.interaction.capabilities.core.AppEntityListener
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures
 import androidx.appactions.interaction.capabilities.core.values.EntityValue
 
-interface Session : BaseSession<Argument, Output> {
+interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
 
     fun getRequiredEntityListener(): AppEntityListener<EntityValue>? = null
 
     companion object {
         @JvmStatic
-        val DEFAULT: Session = object : Session {
-            override fun onFinishAsync(argument: Argument) =
+        val DEFAULT = object : ExecutionSession {
+            override fun onExecuteAsync(arguments: Arguments) =
                 Futures.immediateFuture(
-                    ExecutionResult.getDefaultInstance<Output>(),
+                    ExecutionResult.Builder<Output>().build(),
                 )
         }
     }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Property.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Properties.java
similarity index 63%
rename from appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Property.java
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Properties.java
index 030b5c3..fc9cb05 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Property.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/spec/Properties.java
@@ -19,8 +19,8 @@
 import androidx.annotation.NonNull;
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf;
 import androidx.appactions.interaction.capabilities.core.properties.Entity;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty;
 
 import com.google.auto.value.AutoValue;
 
@@ -28,34 +28,34 @@
 
 /** Testing implementation of a capability Property. */
 @AutoValue
-public abstract class Property {
+public abstract class Properties {
 
     public static Builder newBuilder() {
-        return new AutoValue_Property.Builder();
+        return new AutoValue_Properties.Builder();
     }
 
-    public abstract TypeProperty<Entity> requiredEntityField();
+    public abstract Property<Entity> requiredEntityField();
 
-    public abstract Optional<TypeProperty<StringValue>> optionalStringField();
+    public abstract Optional<Property<StringValue>> optionalStringField();
 
-    public abstract Optional<TypeProperty<TestEnum>> enumField();
+    public abstract Optional<Property<TestEnum>> enumField();
 
-    public abstract Optional<TypeProperty<StringValue>> repeatedStringField();
+    public abstract Optional<Property<StringValue>> repeatedStringField();
 
     /** Builder for the testing Property. */
     @AutoValue.Builder
-    public abstract static class Builder implements BuilderOf<Property> {
+    public abstract static class Builder implements BuilderOf<Properties> {
 
-        public abstract Builder setRequiredEntityField(TypeProperty<Entity> property);
+        public abstract Builder setRequiredEntityField(Property<Entity> property);
 
-        public abstract Builder setOptionalStringField(TypeProperty<StringValue> property);
+        public abstract Builder setOptionalStringField(Property<StringValue> property);
 
-        public abstract Builder setEnumField(TypeProperty<TestEnum> property);
+        public abstract Builder setEnumField(Property<TestEnum> property);
 
-        public abstract Builder setRepeatedStringField(TypeProperty<StringValue> property);
+        public abstract Builder setRepeatedStringField(Property<StringValue> property);
 
         @NonNull
         @Override
-        public abstract Property build();
+        public abstract Properties build();
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
index 477b392..66f19fa 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetExerciseObservation.kt
@@ -16,15 +16,13 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.LocalTime
 import java.util.Optional
 
@@ -34,23 +32,23 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(GetExerciseObservation.Property::class.java)
-        .setArgument(
-            GetExerciseObservation.Argument::class.java,
-            GetExerciseObservation.Argument::Builder
+        .setDescriptor(GetExerciseObservation.Properties::class.java)
+        .setArguments(
+            GetExerciseObservation.Arguments::class.java,
+            GetExerciseObservation.Arguments::Builder
         )
         .setOutput(GetExerciseObservation.Output::class.java)
         .bindOptionalParameter(
             "healthObservation.startTime",
             { property -> Optional.ofNullable(property.startTime) },
-            GetExerciseObservation.Argument.Builder::setStartTime,
+            GetExerciseObservation.Arguments.Builder::setStartTime,
             TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
             TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
         )
         .bindOptionalParameter(
             "healthObservation.endTime",
             { property -> Optional.ofNullable(property.endTime) },
-            GetExerciseObservation.Argument.Builder::setEndTime,
+            GetExerciseObservation.Arguments.Builder::setEndTime,
             TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
             TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
         )
@@ -59,15 +57,15 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class GetExerciseObservation private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setStartTimeProperty(startTime: TypeProperty<LocalTime>): CapabilityBuilder = apply {
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(startTime)
         }
 
-        fun setEndTimeProperty(endTime: TypeProperty<LocalTime>): CapabilityBuilder = apply {
+        fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(endTime)
         }
 
@@ -79,9 +77,9 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val startTime: TypeProperty<LocalTime>?,
-        val endTime: TypeProperty<LocalTime>?
+    class Properties internal constructor(
+        val startTime: Property<LocalTime>?,
+        val endTime: Property<LocalTime>?
     ) {
         override fun toString(): String {
             return "Property(startTime=$startTime, endTime=$endTime)"
@@ -91,7 +89,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (startTime != other.startTime) return false
             if (endTime != other.endTime) return false
@@ -106,32 +104,32 @@
         }
 
         class Builder {
-            private var startTime: TypeProperty<LocalTime>? = null
-            private var endTime: TypeProperty<LocalTime>? = null
+            private var startTime: Property<LocalTime>? = null
+            private var endTime: Property<LocalTime>? = null
 
-            fun setStartTime(startTime: TypeProperty<LocalTime>): Builder =
+            fun setStartTime(startTime: Property<LocalTime>): Builder =
                 apply { this.startTime = startTime }
 
-            fun setEndTime(endTime: TypeProperty<LocalTime>): Builder =
+            fun setEndTime(endTime: Property<LocalTime>): Builder =
                 apply { this.endTime = endTime }
 
-            fun build(): Property = Property(startTime, endTime)
+            fun build(): Properties = Properties(startTime, endTime)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val startTime: LocalTime?,
         val endTime: LocalTime?
     ) {
         override fun toString(): String {
-            return "Argument(startTime=$startTime, endTime=$endTime)"
+            return "Arguments(startTime=$startTime, endTime=$endTime)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (startTime != other.startTime) return false
             if (endTime != other.endTime) return false
@@ -145,7 +143,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var startTime: LocalTime? = null
             private var endTime: LocalTime? = null
 
@@ -155,7 +153,7 @@
             fun setEndTime(endTime: LocalTime): Builder =
                 apply { this.endTime = endTime }
 
-            override fun build(): Argument = Argument(startTime, endTime)
+            override fun build(): Arguments = Arguments(startTime, endTime)
         }
     }
 
@@ -163,7 +161,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
index ef14c26..df9e344 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/GetHealthObservation.kt
@@ -16,15 +16,13 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.LocalTime
 import java.util.Optional
 
@@ -34,23 +32,23 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(GetHealthObservation.Property::class.java)
-        .setArgument(
-            GetHealthObservation.Argument::class.java,
-            GetHealthObservation.Argument::Builder
+        .setDescriptor(GetHealthObservation.Properties::class.java)
+        .setArguments(
+            GetHealthObservation.Arguments::class.java,
+            GetHealthObservation.Arguments::Builder
         )
         .setOutput(GetHealthObservation.Output::class.java)
         .bindOptionalParameter(
             "exerciseObservation.startTime",
             { property -> Optional.ofNullable(property.startTime) },
-            GetHealthObservation.Argument.Builder::setStartTime,
+            GetHealthObservation.Arguments.Builder::setStartTime,
             TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
             TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
         )
         .bindOptionalParameter(
             "exerciseObservation.endTime",
             { property -> Optional.ofNullable(property.endTime) },
-            GetHealthObservation.Argument.Builder::setEndTime,
+            GetHealthObservation.Arguments.Builder::setEndTime,
             TypeConverters.LOCAL_TIME_PARAM_VALUE_CONVERTER,
             TypeConverters.LOCAL_TIME_ENTITY_CONVERTER
         )
@@ -59,15 +57,15 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class GetHealthObservation private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setStartTimeProperty(startTime: TypeProperty<LocalTime>): CapabilityBuilder = apply {
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(startTime)
         }
 
-        fun setEndTimeProperty(endTime: TypeProperty<LocalTime>): CapabilityBuilder = apply {
+        fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(endTime)
         }
 
@@ -79,9 +77,9 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val startTime: TypeProperty<LocalTime>?,
-        val endTime: TypeProperty<LocalTime>?
+    class Properties internal constructor(
+        val startTime: Property<LocalTime>?,
+        val endTime: Property<LocalTime>?
     ) {
         override fun toString(): String {
             return "Property(startTime=$startTime, endTime=$endTime)"
@@ -91,7 +89,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (startTime != other.startTime) return false
             if (endTime != other.endTime) return false
@@ -106,32 +104,32 @@
         }
 
         class Builder {
-            private var startTime: TypeProperty<LocalTime>? = null
-            private var endTime: TypeProperty<LocalTime>? = null
+            private var startTime: Property<LocalTime>? = null
+            private var endTime: Property<LocalTime>? = null
 
-            fun setStartTime(startTime: TypeProperty<LocalTime>): Builder =
+            fun setStartTime(startTime: Property<LocalTime>): Builder =
                 apply { this.startTime = startTime }
 
-            fun setEndTime(endTime: TypeProperty<LocalTime>): Builder =
+            fun setEndTime(endTime: Property<LocalTime>): Builder =
                 apply { this.endTime = endTime }
 
-            fun build(): Property = Property(startTime, endTime)
+            fun build(): Properties = Properties(startTime, endTime)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val startTime: LocalTime?,
         val endTime: LocalTime?
     ) {
         override fun toString(): String {
-            return "Argument(startTime=$startTime, endTime=$endTime)"
+            return "Arguments(startTime=$startTime, endTime=$endTime)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (startTime != other.startTime) return false
             if (endTime != other.endTime) return false
@@ -145,7 +143,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var startTime: LocalTime? = null
             private var endTime: LocalTime? = null
 
@@ -155,7 +153,7 @@
             fun setEndTime(endTime: LocalTime): Builder =
                 apply { this.endTime = endTime }
 
-            override fun build(): Argument = Argument(startTime, endTime)
+            override fun build(): Arguments = Arguments(startTime, endTime)
         }
     }
 
@@ -163,7 +161,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
index 6631322..332207f 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/PauseExercise.kt
@@ -16,16 +16,14 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.util.Optional
 
 /** PauseExercise.kt in interaction-capabilities-fitness */
@@ -34,13 +32,13 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(PauseExercise.Property::class.java)
-        .setArgument(PauseExercise.Argument::class.java, PauseExercise.Argument::Builder)
+        .setDescriptor(PauseExercise.Properties::class.java)
+        .setArguments(PauseExercise.Arguments::class.java, PauseExercise.Arguments::Builder)
         .setOutput(PauseExercise.Output::class.java)
         .bindOptionalParameter(
             "exercise.name",
             { property -> Optional.ofNullable(property.name) },
-            PauseExercise.Argument.Builder::setName,
+            PauseExercise.Arguments.Builder::setName,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER
         )
@@ -49,11 +47,11 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class PauseExercise private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: TypeProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -66,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: TypeProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -77,7 +75,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (name != other.name) return false
 
@@ -89,27 +87,27 @@
         }
 
         class Builder {
-            private var name: TypeProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: TypeProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val name: String?
     ) {
         override fun toString(): String {
-            return "Argument(name=$name)"
+            return "Arguments(name=$name)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (name != other.name) return false
 
@@ -120,13 +118,13 @@
             return name.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var name: String? = null
 
             fun setName(name: String): Builder =
                 apply { this.name = name }
 
-            override fun build(): Argument = Argument(name)
+            override fun build(): Arguments = Arguments(name)
         }
     }
 
@@ -134,7 +132,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
index a2ae19a..491e804 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/ResumeExercise.kt
@@ -16,16 +16,14 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.util.Optional
 
 /** ResumeExercise.kt in interaction-capabilities-fitness */
@@ -34,13 +32,13 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResumeExercise.Property::class.java)
-        .setArgument(ResumeExercise.Argument::class.java, ResumeExercise.Argument::Builder)
+        .setDescriptor(ResumeExercise.Properties::class.java)
+        .setArguments(ResumeExercise.Arguments::class.java, ResumeExercise.Arguments::Builder)
         .setOutput(ResumeExercise.Output::class.java)
         .bindOptionalParameter(
             "exercise.name",
             { property -> Optional.ofNullable(property.name) },
-            ResumeExercise.Argument.Builder::setName,
+            ResumeExercise.Arguments.Builder::setName,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER
         )
@@ -49,11 +47,11 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class ResumeExercise private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: TypeProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -66,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: TypeProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -77,7 +75,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (name != other.name) return false
 
@@ -89,27 +87,27 @@
         }
 
         class Builder {
-            private var name: TypeProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: TypeProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val name: String?
     ) {
         override fun toString(): String {
-            return "Argument(name=$name)"
+            return "Arguments(name=$name)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (name != other.name) return false
 
@@ -120,13 +118,13 @@
             return name.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var name: String? = null
 
             fun setName(name: String): Builder =
                 apply { this.name = name }
 
-            override fun build(): Argument = Argument(name)
+            override fun build(): Arguments = Arguments(name)
         }
     }
 
@@ -134,7 +132,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
index 34c201e..04524b4 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StartExercise.kt
@@ -16,16 +16,14 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.Duration
 import java.util.Optional
 
@@ -35,20 +33,20 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartExercise.Property::class.java)
-        .setArgument(StartExercise.Argument::class.java, StartExercise.Argument::Builder)
+        .setDescriptor(StartExercise.Properties::class.java)
+        .setArguments(StartExercise.Arguments::class.java, StartExercise.Arguments::Builder)
         .setOutput(StartExercise.Output::class.java)
         .bindOptionalParameter(
             "exercise.duration",
             { property -> Optional.ofNullable(property.duration) },
-            StartExercise.Argument.Builder::setDuration,
+            StartExercise.Arguments.Builder::setDuration,
             TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
             TypeConverters.DURATION_ENTITY_CONVERTER
         )
         .bindOptionalParameter(
             "exercise.name",
             { property -> Optional.ofNullable(property.name) },
-            StartExercise.Argument.Builder::setName,
+            StartExercise.Arguments.Builder::setName,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER
         )
@@ -57,30 +55,30 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class StartExercise private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        fun setDurationProperty(duration: TypeProperty<Duration>): CapabilityBuilder =
+        fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder =
             apply {
-                Property.Builder().setDuration(duration).build()
+                Properties.Builder().setDuration(duration).build()
             }
 
-        fun setNameProperty(name: TypeProperty<StringValue>): CapabilityBuilder =
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
-                Property.Builder().setName(name).build()
+                Properties.Builder().setName(name).build()
             }
 
         override fun build(): Capability {
             // TODO(b/268369632): No-op remove empty property builder after Property od removed
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val duration: TypeProperty<Duration>?,
-        val name: TypeProperty<StringValue>?
+    class Properties internal constructor(
+        val duration: Property<Duration>?,
+        val name: Property<StringValue>?
     ) {
         override fun toString(): String {
             return "Property(duration=$duration, name=$name)"
@@ -90,7 +88,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (duration != other.duration) return false
             if (name != other.name) return false
@@ -105,32 +103,32 @@
         }
 
         class Builder {
-            private var duration: TypeProperty<Duration>? = null
-            private var name: TypeProperty<StringValue>? = null
+            private var duration: Property<Duration>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setDuration(duration: TypeProperty<Duration>): Builder =
+            fun setDuration(duration: Property<Duration>): Builder =
                 apply { this.duration = duration }
 
-            fun setName(name: TypeProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(duration, name)
+            fun build(): Properties = Properties(duration, name)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val duration: Duration?,
         val name: String?
     ) {
         override fun toString(): String {
-            return "Argument(duration=$duration, name=$name)"
+            return "Arguments(duration=$duration, name=$name)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (duration != other.duration) return false
             if (name != other.name) return false
@@ -144,7 +142,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var duration: Duration? = null
             private var name: String? = null
 
@@ -154,7 +152,7 @@
             fun setName(name: String): Builder =
                 apply { this.name = name }
 
-            override fun build(): Argument = Argument(duration, name)
+            override fun build(): Arguments = Arguments(duration, name)
         }
     }
 
@@ -162,7 +160,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
index a03a356..09690c52 100644
--- a/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
+++ b/appactions/interaction/interaction-capabilities-fitness/src/main/java/androidx/appactions/interaction/capabilities/fitness/fitness/StopExercise.kt
@@ -16,16 +16,14 @@
 
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.CapabilityFactory
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
 import java.util.Optional
 
 /** StopExercise.kt in interaction-capabilities-fitness */
@@ -34,13 +32,13 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopExercise.Property::class.java)
-        .setArgument(StopExercise.Argument::class.java, StopExercise.Argument::Builder)
+        .setDescriptor(StopExercise.Properties::class.java)
+        .setArguments(StopExercise.Arguments::class.java, StopExercise.Arguments::Builder)
         .setOutput(StopExercise.Output::class.java)
         .bindOptionalParameter(
             "exercise.name",
             { property -> Optional.ofNullable(property.name) },
-            StopExercise.Argument.Builder::setName,
+            StopExercise.Arguments.Builder::setName,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER
         )
@@ -49,11 +47,11 @@
 @CapabilityFactory(name = CAPABILITY_NAME)
 class StopExercise private constructor() {
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: TypeProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -66,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: TypeProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -77,7 +75,7 @@
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (name != other.name) return false
 
@@ -89,27 +87,27 @@
         }
 
         class Builder {
-            private var name: TypeProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: TypeProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val name: String?
     ) {
         override fun toString(): String {
-            return "Argument(name=$name)"
+            return "Arguments(name=$name)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass !== other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (name != other.name) return false
 
@@ -120,13 +118,13 @@
             return name.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var name: String? = null
 
             fun setName(name: String): Builder =
                 apply { this.name = name }
 
-            override fun build(): Argument = Argument(name)
+            override fun build(): Arguments = Arguments(name)
         }
     }
 
@@ -134,7 +132,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
index fddb52a..f4a5294 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/PauseTimer.kt
@@ -17,13 +17,11 @@
 package androidx.appactions.interaction.capabilities.productivity
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.proto.ParamValue
@@ -36,13 +34,13 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(PauseTimer.Property::class.java)
-        .setArgument(PauseTimer.Argument::class.java, PauseTimer.Argument::Builder)
+        .setDescriptor(PauseTimer.Properties::class.java)
+        .setArguments(PauseTimer.Arguments::class.java, PauseTimer.Arguments::Builder)
         .setOutput(PauseTimer.Output::class.java)
         .bindRepeatedParameter(
             "timer",
             { property -> Optional.ofNullable(property.timerList) },
-            PauseTimer.Argument.Builder::setTimerList,
+            PauseTimer.Arguments.Builder::setTimerList,
             TimerValue.PARAM_VALUE_CONVERTER,
             TimerValue.ENTITY_CONVERTER
         )
@@ -57,25 +55,24 @@
 class PauseTimer private constructor() {
 
     class CapabilityBuilder :
-        CapabilityBuilderBase<
+        Capability.Builder<
             CapabilityBuilder,
-            Property,
-            Argument,
+            Properties,
+            Arguments,
             Output,
             Confirmation,
-            TaskUpdater,
-            Session,
+            ExecutionSession,
         >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property
+    class Properties
     internal constructor(
-        val timerList: TypeProperty<TimerValue>?,
+        val timerList: Property<TimerValue>?,
     ) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
@@ -85,7 +82,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (timerList != other.timerList) return false
 
@@ -97,29 +94,29 @@
         }
 
         class Builder {
-            private var timerList: TypeProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: TypeProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
-    class Argument
+    class Arguments
     internal constructor(
         val timerList: List<TimerValue>?,
     ) {
         override fun toString(): String {
-            return "Argument(timerList=$timerList)"
+            return "Arguments(timerList=$timerList)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (timerList != other.timerList) return false
 
@@ -130,14 +127,14 @@
             return timerList.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var timerList: List<TimerValue>? = null
 
             fun setTimerList(timerList: List<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            override fun build(): Argument = Argument(timerList)
+            override fun build(): Arguments = Arguments(timerList)
         }
     }
 
@@ -203,7 +200,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
index f8c208b..ec8fea6 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
@@ -17,13 +17,11 @@
 package androidx.appactions.interaction.capabilities.productivity
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.proto.ParamValue
@@ -36,13 +34,13 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResetTimer.Property::class.java)
-        .setArgument(ResetTimer.Argument::class.java, ResetTimer.Argument::Builder)
+        .setDescriptor(ResetTimer.Properties::class.java)
+        .setArguments(ResetTimer.Arguments::class.java, ResetTimer.Arguments::Builder)
         .setOutput(ResetTimer.Output::class.java)
         .bindRepeatedParameter(
             "timer",
             { property -> Optional.ofNullable(property.timerList) },
-            ResetTimer.Argument.Builder::setTimerList,
+            ResetTimer.Arguments.Builder::setTimerList,
             TimerValue.PARAM_VALUE_CONVERTER,
             TimerValue.ENTITY_CONVERTER
         )
@@ -57,17 +55,17 @@
 class ResetTimer private constructor() {
 
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
         >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(val timerList: TypeProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -76,7 +74,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (timerList != other.timerList) return false
 
@@ -88,26 +86,26 @@
         }
 
         class Builder {
-            private var timerList: TypeProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: TypeProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
-    class Argument internal constructor(val timerList: List<TimerValue>?) {
+    class Arguments internal constructor(val timerList: List<TimerValue>?) {
         override fun toString(): String {
-            return "Argument(timerList=$timerList)"
+            return "Arguments(timerList=$timerList)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (timerList != other.timerList) return false
 
@@ -118,14 +116,14 @@
             return timerList.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var timerList: List<TimerValue>? = null
 
             fun setTimerList(
                 timerList: List<TimerValue>,
             ): Builder = apply { this.timerList = timerList }
 
-            override fun build(): Argument = Argument(timerList)
+            override fun build(): Arguments = Arguments(timerList)
         }
     }
 
@@ -191,7 +189,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
index 8448d93..d8b2fb0 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
@@ -17,13 +17,11 @@
 package androidx.appactions.interaction.capabilities.productivity
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.proto.ParamValue
@@ -36,13 +34,13 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResumeTimer.Property::class.java)
-        .setArgument(ResumeTimer.Argument::class.java, ResumeTimer.Argument::Builder)
+        .setDescriptor(ResumeTimer.Properties::class.java)
+        .setArguments(ResumeTimer.Arguments::class.java, ResumeTimer.Arguments::Builder)
         .setOutput(ResumeTimer.Output::class.java)
         .bindRepeatedParameter(
             "timer",
             { property -> Optional.ofNullable(property.timerList) },
-            ResumeTimer.Argument.Builder::setTimerList,
+            ResumeTimer.Arguments.Builder::setTimerList,
             TimerValue.PARAM_VALUE_CONVERTER,
             TimerValue.ENTITY_CONVERTER
         )
@@ -57,17 +55,17 @@
 class ResumeTimer private constructor() {
 
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
         >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(val timerList: TypeProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -76,7 +74,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (timerList != other.timerList) return false
 
@@ -88,26 +86,26 @@
         }
 
         class Builder {
-            private var timerList: TypeProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: TypeProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
-    class Argument internal constructor(val timerList: List<TimerValue>?) {
+    class Arguments internal constructor(val timerList: List<TimerValue>?) {
         override fun toString(): String {
-            return "Argument(timerList=$timerList)"
+            return "Arguments(timerList=$timerList)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (timerList != other.timerList) return false
 
@@ -118,14 +116,14 @@
             return timerList.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var timerList: List<TimerValue>? = null
 
             fun setTimerList(
                 timerList: List<TimerValue>,
             ): Builder = apply { this.timerList = timerList }
 
-            override fun build(): Argument = Argument(timerList)
+            override fun build(): Arguments = Arguments(timerList)
         }
     }
 
@@ -191,7 +189,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
index e1c80e0..360b356 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StartTimer.kt
@@ -17,16 +17,14 @@
 package androidx.appactions.interaction.capabilities.productivity
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
-import androidx.appactions.interaction.capabilities.core.SessionFactory
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
+import androidx.appactions.interaction.capabilities.core.ExecutionSessionFactory
 import androidx.appactions.interaction.capabilities.core.ValueListener
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
 import androidx.appactions.interaction.capabilities.core.impl.task.TaskHandler
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
@@ -36,34 +34,33 @@
 import androidx.appactions.interaction.protobuf.Value
 import java.time.Duration
 import java.util.Optional
-import java.util.function.Supplier
 
 /** StartTimer.kt in interaction-capabilities-productivity */
 private const val CAPABILITY_NAME = "actions.intent.START_TIMER"
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartTimer.Property::class.java)
-        .setArgument(StartTimer.Argument::class.java, StartTimer.Argument::Builder)
+        .setDescriptor(StartTimer.Properties::class.java)
+        .setArguments(StartTimer.Arguments::class.java, StartTimer.Arguments::Builder)
         .setOutput(StartTimer.Output::class.java)
         .bindOptionalParameter(
             "timer.identifier",
             { property -> Optional.ofNullable(property.identifier) },
-            StartTimer.Argument.Builder::setIdentifier,
+            StartTimer.Arguments.Builder::setIdentifier,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
         )
         .bindOptionalParameter(
             "timer.name",
             { property -> Optional.ofNullable(property.name) },
-            StartTimer.Argument.Builder::setName,
+            StartTimer.Arguments.Builder::setName,
             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
             TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
         )
         .bindOptionalParameter(
             "timer.duration",
             { property -> Optional.ofNullable(property.duration) },
-            StartTimer.Argument.Builder::setDuration,
+            StartTimer.Arguments.Builder::setDuration,
             TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
             TypeConverters.DURATION_ENTITY_CONVERTER,
         )
@@ -74,7 +71,7 @@
         )
         .build()
 
-private val SESSION_BRIDGE = SessionBridge<StartTimer.Session, StartTimer.Confirmation> {
+private val SESSION_BRIDGE = SessionBridge<StartTimer.ExecutionSession, StartTimer.Confirmation> {
         session ->
     val taskHandlerBuilder = TaskHandler.Builder<StartTimer.Confirmation>()
     session.nameListener?.let {
@@ -98,26 +95,23 @@
 class StartTimer private constructor() {
 
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session,
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession,
             >(ACTION_SPEC) {
 
-        override val sessionBridge: SessionBridge<Session, Confirmation> = SESSION_BRIDGE
-        override val sessionUpdaterSupplier: Supplier<TaskUpdater> = Supplier {
-            TaskUpdater()
-        }
+        override val sessionBridge: SessionBridge<ExecutionSession, Confirmation> = SESSION_BRIDGE
 
-        public override fun setSessionFactory(
-            sessionFactory: SessionFactory<Session>,
-        ): CapabilityBuilder = super.setSessionFactory(sessionFactory)
+        public override fun setExecutionSessionFactory(
+            sessionFactory: ExecutionSessionFactory<ExecutionSession>,
+        ): CapabilityBuilder = super.setExecutionSessionFactory(sessionFactory)
 
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
-    interface Session : BaseSession<Argument, Output> {
+    interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
         val nameListener: ValueListener<String>?
             get() = null
         val durationListener: ValueListener<Duration>?
@@ -125,11 +119,11 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property
+    class Properties
     internal constructor(
-        val identifier: TypeProperty<StringValue>?,
-        val name: TypeProperty<StringValue>?,
-        val duration: TypeProperty<Duration>?,
+        val identifier: Property<StringValue>?,
+        val name: Property<StringValue>?,
+        val duration: Property<Duration>?,
     ) {
         override fun toString(): String {
             return "Property(identifier=$identifier,name=$name,duration=$duration}"
@@ -139,7 +133,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (identifier != other.identifier) return false
             if (name != other.name) return false
@@ -156,38 +150,38 @@
         }
 
         class Builder {
-            private var identifier: TypeProperty<StringValue>? = null
-            private var name: TypeProperty<StringValue>? = null
-            private var duration: TypeProperty<Duration>? = null
+            private var identifier: Property<StringValue>? = null
+            private var name: Property<StringValue>? = null
+            private var duration: Property<Duration>? = null
 
-            fun setIdentifier(identifier: TypeProperty<StringValue>): Builder = apply {
+            fun setIdentifier(identifier: Property<StringValue>): Builder = apply {
                 this.identifier = identifier
             }
 
-            fun setName(name: TypeProperty<StringValue>): Builder = apply { this.name = name }
+            fun setName(name: Property<StringValue>): Builder = apply { this.name = name }
 
-            fun setDuration(duration: TypeProperty<Duration>): Builder = apply {
+            fun setDuration(duration: Property<Duration>): Builder = apply {
                 this.duration = duration
             }
 
-            fun build(): Property = Property(identifier, name, duration)
+            fun build(): Properties = Properties(identifier, name, duration)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val identifier: String?,
         val name: String?,
         val duration: Duration?,
     ) {
         override fun toString(): String {
-            return "Argument(identifier=$identifier,name=$name,duration=$duration)"
+            return "Arguments(identifier=$identifier,name=$name,duration=$duration)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (identifier != other.identifier) return false
             if (name != other.name) return false
@@ -203,7 +197,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var identifier: String? = null
             private var name: String? = null
             private var duration: Duration? = null
@@ -214,7 +208,7 @@
 
             fun setDuration(duration: Duration): Builder = apply { this.duration = duration }
 
-            override fun build(): Argument = Argument(identifier, name, duration)
+            override fun build(): Arguments = Arguments(identifier, name, duration)
         }
     }
 
@@ -279,6 +273,4 @@
     }
 
     class Confirmation internal constructor()
-
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-}
+    }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
index d01f090..c018c60 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
@@ -17,13 +17,11 @@
 package androidx.appactions.interaction.capabilities.productivity
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.proto.ParamValue
@@ -36,13 +34,13 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopTimer.Property::class.java)
-        .setArgument(StopTimer.Argument::class.java, StopTimer.Argument::Builder)
+        .setDescriptor(StopTimer.Properties::class.java)
+        .setArguments(StopTimer.Arguments::class.java, StopTimer.Arguments::Builder)
         .setOutput(StopTimer.Output::class.java)
         .bindRepeatedParameter(
             "timer",
             { property -> Optional.ofNullable(property.timerList) },
-            StopTimer.Argument.Builder::setTimerList,
+            StopTimer.Arguments.Builder::setTimerList,
             TimerValue.PARAM_VALUE_CONVERTER,
             TimerValue.ENTITY_CONVERTER
         )
@@ -57,17 +55,17 @@
 class StopTimer private constructor() {
 
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
-        >(ACTION_SPEC) {
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
+            >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(val timerList: TypeProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -76,7 +74,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (timerList != other.timerList) return false
 
@@ -88,26 +86,26 @@
         }
 
         class Builder {
-            private var timerList: TypeProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: TypeProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
-    class Argument internal constructor(val timerList: List<TimerValue>?) {
+    class Arguments internal constructor(val timerList: List<TimerValue>?) {
         override fun toString(): String {
-            return "Argument(timerList=$timerList)"
+            return "Arguments(timerList=$timerList)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (timerList != other.timerList) return false
 
@@ -118,14 +116,14 @@
             return timerList.hashCode()
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var timerList: List<TimerValue>? = null
 
             fun setTimerList(
                 timerList: List<TimerValue>,
             ): Builder = apply { this.timerList = timerList }
 
-            override fun build(): Argument = Argument(timerList)
+            override fun build(): Arguments = Arguments(timerList)
         }
     }
 
@@ -191,7 +189,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
index 9cf562d..79e0bd3 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartEmergencySharing.kt
@@ -16,13 +16,11 @@
 
 package androidx.appactions.interaction.capabilities.safety
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.capabilities.core.values.executionstatus.NoInternetConnection
@@ -39,10 +37,10 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartEmergencySharing.Property::class.java)
-        .setArgument(
-            StartEmergencySharing.Argument::class.java,
-            StartEmergencySharing.Argument::Builder
+        .setDescriptor(StartEmergencySharing.Properties::class.java)
+        .setArguments(
+            StartEmergencySharing.Arguments::class.java,
+            StartEmergencySharing.Arguments::Builder
         )
         .setOutput(StartEmergencySharing.Output::class.java)
         .bindOptionalOutput(
@@ -56,21 +54,21 @@
 class StartEmergencySharing private constructor() {
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session,
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession,
             >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property())
+            super.setProperty(Properties())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor()
+    class Properties internal constructor()
 
-    class Argument internal constructor() {
-        class Builder : BuilderOf<Argument> {
-            override fun build(): Argument = Argument()
+    class Arguments internal constructor() {
+        class Builder : BuilderOf<Arguments> {
+            override fun build(): Arguments = Arguments()
         }
     }
 
@@ -169,7 +167,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
index 3c91f16..0bf2a33 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StartSafetyCheck.kt
@@ -17,15 +17,13 @@
 package androidx.appactions.interaction.capabilities.safety
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.ParamValueConverter
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters.SAFETY_CHECK_TYPE_SPEC
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SafetyCheck
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
@@ -46,20 +44,20 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartSafetyCheck.Property::class.java)
-        .setArgument(StartSafetyCheck.Argument::class.java, StartSafetyCheck.Argument::Builder)
+        .setDescriptor(StartSafetyCheck.Properties::class.java)
+        .setArguments(StartSafetyCheck.Arguments::class.java, StartSafetyCheck.Arguments::Builder)
         .setOutput(StartSafetyCheck.Output::class.java)
         .bindOptionalParameter(
             "safetyCheck.duration",
             { property -> Optional.ofNullable(property.duration) },
-            StartSafetyCheck.Argument.Builder::setDuration,
+            StartSafetyCheck.Arguments.Builder::setDuration,
             TypeConverters.DURATION_PARAM_VALUE_CONVERTER,
             TypeConverters.DURATION_ENTITY_CONVERTER
         )
         .bindOptionalParameter(
             "safetyCheck.checkInTime",
             { property -> Optional.ofNullable(property.checkInTime) },
-            StartSafetyCheck.Argument.Builder::setCheckInTime,
+            StartSafetyCheck.Arguments.Builder::setCheckInTime,
             TypeConverters.ZONED_DATETIME_PARAM_VALUE_CONVERTER,
             TypeConverters.ZONED_DATETIME_ENTITY_CONVERTER
         )
@@ -79,20 +77,20 @@
 class StartSafetyCheck private constructor() {
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
         override fun build(): Capability {
             // TODO(b/268369632): No-op remove empty property builder after Property od removed
-            super.setProperty(Property.Builder().build())
+            super.setProperty(Properties.Builder().build())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val duration: TypeProperty<Duration>?,
-        val checkInTime: TypeProperty<ZonedDateTime>?
+    class Properties internal constructor(
+        val duration: Property<Duration>?,
+        val checkInTime: Property<ZonedDateTime>?
     ) {
         override fun toString(): String {
             return "Property(duration=$duration, checkInTime=$checkInTime)"
@@ -102,7 +100,7 @@
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Property
+            other as Properties
 
             if (duration != other.duration) return false
             if (checkInTime != other.checkInTime) return false
@@ -117,33 +115,33 @@
         }
 
         class Builder {
-            private var duration: TypeProperty<Duration>? = null
+            private var duration: Property<Duration>? = null
 
-            private var checkInTime: TypeProperty<ZonedDateTime>? = null
+            private var checkInTime: Property<ZonedDateTime>? = null
 
-            fun setDuration(duration: TypeProperty<Duration>): Builder =
+            fun setDuration(duration: Property<Duration>): Builder =
                 apply { this.duration = duration }
 
-            fun setCheckInTime(checkInTime: TypeProperty<ZonedDateTime>): Builder =
+            fun setCheckInTime(checkInTime: Property<ZonedDateTime>): Builder =
                 apply { this.checkInTime = checkInTime }
 
-            fun build(): Property = Property(duration, checkInTime)
+            fun build(): Properties = Properties(duration, checkInTime)
         }
     }
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val duration: Duration?,
         val checkInTime: ZonedDateTime?
     ) {
         override fun toString(): String {
-            return "Argument(duration=$duration, checkInTime=$checkInTime)"
+            return "Arguments(duration=$duration, checkInTime=$checkInTime)"
         }
 
         override fun equals(other: Any?): Boolean {
             if (this === other) return true
             if (javaClass != other?.javaClass) return false
 
-            other as Argument
+            other as Arguments
 
             if (duration != other.duration) return false
             if (checkInTime != other.checkInTime) return false
@@ -157,7 +155,7 @@
             return result
         }
 
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var duration: Duration? = null
 
             private var checkInTime: ZonedDateTime? = null
@@ -168,7 +166,7 @@
             fun setCheckInTime(checkInTime: ZonedDateTime): Builder =
                 apply { this.checkInTime = checkInTime }
 
-            override fun build(): Argument = Argument(duration, checkInTime)
+            override fun build(): Arguments = Arguments(duration, checkInTime)
         }
     }
 
@@ -286,7 +284,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
index cfa0500..1224831 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopEmergencySharing.kt
@@ -16,13 +16,11 @@
 
 package androidx.appactions.interaction.capabilities.safety
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.capabilities.core.values.executionstatus.ActionNotInProgress
@@ -39,10 +37,10 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopEmergencySharing.Property::class.java)
-        .setArgument(
-            StopEmergencySharing.Argument::class.java,
-            StopEmergencySharing.Argument::Builder
+        .setDescriptor(StopEmergencySharing.Properties::class.java)
+        .setArguments(
+            StopEmergencySharing.Arguments::class.java,
+            StopEmergencySharing.Arguments::Builder
         )
         .setOutput(StopEmergencySharing.Output::class.java)
         .bindOptionalOutput(
@@ -56,21 +54,21 @@
 class StopEmergencySharing private constructor() {
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session,
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession,
             >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property())
+            super.setProperty(Properties())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor()
+    class Properties internal constructor()
 
-    class Argument internal constructor() {
-        class Builder : BuilderOf<Argument> {
-            override fun build(): Argument = Argument()
+    class Arguments internal constructor() {
+        class Builder : BuilderOf<Arguments> {
+            override fun build(): Arguments = Arguments()
         }
     }
 
@@ -169,7 +167,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
index 543bb0a..01d3ff9 100644
--- a/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
+++ b/appactions/interaction/interaction-capabilities-safety/src/main/java/androidx/appactions/interaction/capabilities/safety/StopSafetyCheck.kt
@@ -16,13 +16,11 @@
 
 package androidx.appactions.interaction.capabilities.safety
 
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
 import androidx.appactions.interaction.capabilities.core.values.executionstatus.ActionNotInProgress
@@ -39,8 +37,8 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopSafetyCheck.Property::class.java)
-        .setArgument(StopSafetyCheck.Argument::class.java, StopSafetyCheck.Argument::Builder)
+        .setDescriptor(StopSafetyCheck.Properties::class.java)
+        .setArguments(StopSafetyCheck.Arguments::class.java, StopSafetyCheck.Arguments::Builder)
         .setOutput(StopSafetyCheck.Output::class.java)
         .bindOptionalOutput(
             "executionStatus",
@@ -53,21 +51,21 @@
 class StopSafetyCheck private constructor() {
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
-        CapabilityBuilderBase<
-            CapabilityBuilder, Property, Argument, Output, Confirmation, TaskUpdater, Session
+        Capability.Builder<
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
         override fun build(): Capability {
-            super.setProperty(Property())
+            super.setProperty(Properties())
             return super.build()
         }
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor()
+    class Properties internal constructor()
 
-    class Argument internal constructor() {
-        class Builder : BuilderOf<Argument> {
-            override fun build(): Argument = Argument()
+    class Arguments internal constructor() {
+        class Builder : BuilderOf<Arguments> {
+            override fun build(): Arguments = Arguments()
         }
     }
 
@@ -166,7 +164,5 @@
 
     class Confirmation internal constructor()
 
-    class TaskUpdater internal constructor() : AbstractTaskUpdater()
-
-    sealed interface Session : BaseSession<Argument, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
diff --git a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/FakeCallbackInternal.kt b/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/FakeCallbackInternal.kt
index d964c36..960f8d0 100644
--- a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/FakeCallbackInternal.kt
+++ b/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/FakeCallbackInternal.kt
@@ -17,19 +17,17 @@
 package androidx.appactions.interaction.capabilities.testing.internal
 
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal
-import androidx.appactions.interaction.capabilities.core.impl.FulfillmentResult
 import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
+import androidx.appactions.interaction.capabilities.core.impl.FulfillmentResult
 import androidx.appactions.interaction.proto.FulfillmentResponse
 import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
 
 /**
  * A fake CallbackInternal instance being used for testing to receive the [FulfillmentResult]
  * containing either [FulfillmentResponse] or [ErrorStatusInternal]
  */
 class FakeCallbackInternal constructor(
-    private val timeoutMs: Long = TestingUtils.CB_TIMEOUT
+    private val timeoutMs: Long = TestingUtils.CB_TIMEOUT,
 ) : CallbackInternal {
 
     private val completer = CompletableDeferred<FulfillmentResult>()
@@ -42,7 +40,7 @@
         completer.complete(FulfillmentResult(errorStatus))
     }
 
-    fun receiveResponse(): FulfillmentResult = runBlocking {
-        withTimeout(timeoutMs) { completer.await() }
+    fun receiveResponse(): FulfillmentResult = with(TestingUtils) {
+        completer.awaitSync(timeoutMs)
     }
-}
\ No newline at end of file
+}
diff --git a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/SettableFutureWrapper.kt b/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/SettableFutureWrapper.kt
deleted file mode 100644
index 6166d4b..0000000
--- a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/SettableFutureWrapper.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.capabilities.testing.internal
-
-import androidx.concurrent.futures.CallbackToFutureAdapter
-import com.google.common.util.concurrent.ListenableFuture
-
-class SettableFutureWrapper<V> {
-    private var mCompleter: CallbackToFutureAdapter.Completer<V>? = null
-    private var mFuture: ListenableFuture<V> =
-        CallbackToFutureAdapter.getFuture { completer: CallbackToFutureAdapter.Completer<V> ->
-            mCompleter = completer
-            "SettableFutureWrapper"
-        }
-
-    fun getFuture(): ListenableFuture<V> {
-        return mFuture
-    }
-
-    fun set(result: V): Boolean {
-        return mCompleter!!.set(result)
-    }
-
-    fun setException(t: Throwable?): Boolean {
-        return mCompleter!!.setException(t!!)
-    }
-}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/TestingUtils.kt b/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/TestingUtils.kt
index b0c465b..e570807 100644
--- a/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/TestingUtils.kt
+++ b/appactions/interaction/interaction-capabilities-testing/src/main/java/androidx/appactions/interaction/capabilities/testing/internal/TestingUtils.kt
@@ -19,6 +19,9 @@
 import androidx.appactions.interaction.capabilities.core.ActionExecutorAsync
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
 
 object TestingUtils {
     // use this timeout for things that should take negligible time.
@@ -26,11 +29,19 @@
     // use this timeout for waiting an arbitrary period of time.
     const val BLOCKING_TIMEOUT = 300L
 
-    fun <ArgumentT, OutputT> createFakeActionExecutor(): ActionExecutorAsync<ArgumentT, OutputT> {
-        return ActionExecutorAsync { _: ArgumentT ->
+    fun <ArgumentsT, OutputT> createFakeActionExecutor(): ActionExecutorAsync<ArgumentsT, OutputT> {
+        return ActionExecutorAsync { _: ArgumentsT ->
             Futures.immediateFuture(
-                ExecutionResult.getDefaultInstance(),
+                ExecutionResult.Builder<OutputT>().build(),
             )
         }
     }
+
+    /** Blocks the current thread until the Deferred is completed, or times out. */
+    fun <T> Deferred<T>.awaitSync(timeoutMs: Long = CB_TIMEOUT): T =
+        runBlocking {
+            withTimeout(timeoutMs) {
+                [email protected]()
+            }
+        }
 }
diff --git a/appactions/interaction/interaction-service/build.gradle b/appactions/interaction/interaction-service/build.gradle
index 0f38bdc..3c69353 100644
--- a/appactions/interaction/interaction-service/build.gradle
+++ b/appactions/interaction/interaction-service/build.gradle
@@ -44,6 +44,7 @@
     implementation(libs.grpcAndroid)
     implementation(libs.grpcBinder)
     implementation(libs.grpcStub)
+    implementation(libs.kotlinCoroutinesCore)
     implementation(libs.kotlinStdlib)
     implementation(libs.jsr250)
 
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
index 1c260b8..623fc0f 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionService.kt
@@ -22,6 +22,7 @@
 import android.util.Log
 import androidx.annotation.CallSuper
 import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.entity.EntityProvider
 import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc
 import io.grpc.Server
 import io.grpc.binder.AndroidComponentAddress
@@ -47,6 +48,13 @@
     abstract val registeredCapabilities: List<Capability>
 
     /**
+     * Called by the system once after the Assistant binds to the service.
+     *
+     * @return the list of EntityProvider that this service supports.
+     */
+    abstract val registeredEntityProviders: List<EntityProvider<*>>
+
+    /**
      * A list of [AppVerificationInfo] which define who is allowed to interact with the app's bound
      * service. This gives control over which clients are allowed to communicate with the service.
      *
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.java b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.java
deleted file mode 100644
index f4aaf5d..0000000
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.appactions.interaction.service;
-
-import android.util.Log;
-import android.util.SizeF;
-import android.widget.RemoteViews;
-import android.widget.RemoteViewsService.RemoteViewsFactory;
-
-import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.Capability;
-import androidx.appactions.interaction.capabilities.core.HostProperties;
-import androidx.appactions.interaction.capabilities.core.LibInfo;
-import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper;
-import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession;
-import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal;
-import androidx.appactions.interaction.capabilities.core.impl.concurrent.FutureCallback;
-import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures;
-import androidx.appactions.interaction.capabilities.core.impl.utils.CapabilityLogger;
-import androidx.appactions.interaction.capabilities.core.impl.utils.LoggerInternal;
-import androidx.appactions.interaction.proto.AppActionsContext;
-import androidx.appactions.interaction.proto.FulfillmentRequest;
-import androidx.appactions.interaction.proto.FulfillmentResponse;
-import androidx.appactions.interaction.proto.GroundingRequest;
-import androidx.appactions.interaction.proto.GroundingResponse;
-import androidx.appactions.interaction.proto.Version;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc.AppInteractionServiceImplBase;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionResponse;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.RemoteViewsInfo;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Request;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Response;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionRequest;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionResponse;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Status.Code;
-import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.UiUpdate;
-import androidx.concurrent.futures.CallbackToFutureAdapter;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-import io.grpc.Status;
-import io.grpc.StatusException;
-import io.grpc.StatusRuntimeException;
-import io.grpc.stub.StreamObserver;
-
-/**
- * Implementation of {@link AppInteractionServiceImplBase} generated from the GRPC proto file. This
- * class delegates the requests to the appropriate capability session.
- */
-final class AppInteractionServiceGrpcImpl extends AppInteractionServiceImplBase {
-
-    private static final String TAG = "ActionsServiceGrpcImpl";
-
-    static final String ERROR_NO_SESSION = "Session not available";
-    static final String ERROR_NO_FULFILLMENT_REQUEST = "Fulfillment request missing";
-    static final String ERROR_NO_ACTION_CAPABILITY = "Capability was not found";
-    static final String ERROR_SESSION_ENDED = "Session already ended";
-    private static final String ERROR_NO_COLLECTION_SUPPORT =
-            "Session doesn't support collection view";
-    private static final String ERROR_NO_UI = "No UI set";
-    private static final String ERROR_MULTIPLE_UI_TYPES =
-            "Multiple UI types used in current session";
-
-    final AppInteractionService mAppInteractionService;
-    List<Capability> mRegisteredCapabilities = new ArrayList<>();
-
-    static {
-        LoggerInternal.setLogger(
-                new CapabilityLogger() {
-                    @Override
-                    public void log(
-                            @NonNull LogLevel logLevel,
-                            @NonNull String logTag,
-                            @NonNull String message) {
-                        switch (logLevel) {
-                            case ERROR:
-                                Log.e(logTag, message);
-                                break;
-                            case WARN:
-                                Log.w(logTag, message);
-                                break;
-                            case INFO:
-                                Log.i(logTag, message);
-                                break;
-                        }
-                    }
-
-                    @Override
-                    public void log(
-                            @NonNull LogLevel logLevel,
-                            @NonNull String logTag,
-                            @NonNull String message,
-                            @NonNull Throwable throwable) {
-                        switch (logLevel) {
-                            case ERROR:
-                                Log.e(logTag, message, throwable);
-                                break;
-                            case WARN:
-                                Log.w(logTag, message, throwable);
-                                break;
-                            case INFO:
-                                Log.i(logTag, message, throwable);
-                                break;
-                        }
-                    }
-                });
-    }
-
-    AppInteractionServiceGrpcImpl(AppInteractionService mAppInteractionService) {
-        this.mAppInteractionService = mAppInteractionService;
-    }
-
-    @Override
-    public StreamObserver<StartSessionRequest> startUpSession(
-            StreamObserver<StartSessionResponse> responseObserver) {
-        return new StartSessionRequestObserver(responseObserver);
-    }
-
-    private final class StartSessionRequestObserver implements StreamObserver<StartSessionRequest> {
-        private final StreamObserver<StartSessionResponse> mStartSessionResponseObserver;
-        // Every AppInteractionService connection is defined by this streaming RPC connection.
-        // There should only be one session tied to each gRPC impl instance.
-        private String mCurrentSessionId = null;
-
-        StartSessionRequestObserver(StreamObserver<StartSessionResponse> responseObserver) {
-            this.mStartSessionResponseObserver = responseObserver;
-        }
-
-        @Override
-        public void onNext(StartSessionRequest request) {
-            if (mCurrentSessionId != null) {
-                return;
-            }
-            mCurrentSessionId = request.getSessionIdentifier();
-            if (mRegisteredCapabilities.isEmpty()) {
-                mRegisteredCapabilities = mAppInteractionService.getRegisteredCapabilities();
-            }
-            Optional<Capability> targetCapability =
-                    mRegisteredCapabilities.stream()
-                            .filter(cap -> request.getIdentifier().equals(cap.getId()))
-                            .findFirst();
-            if (!targetCapability.isPresent()) {
-                mStartSessionResponseObserver.onError(
-                        new StatusRuntimeException(
-                                Status.FAILED_PRECONDITION.withDescription(
-                                        ERROR_NO_ACTION_CAPABILITY)));
-                return;
-            }
-            HostProperties hostProperties =
-                    new HostProperties.Builder()
-                            .setMaxHostSizeDp(new SizeF(
-                                    request.getHostProperties().getHostViewHeightDp(),
-                                    request.getHostProperties().getHostViewWidthDp()))
-                            .build();
-            CapabilitySession session = targetCapability.get().createSession(
-                    mCurrentSessionId, hostProperties);
-            SessionManager.INSTANCE.putSession(mCurrentSessionId, session);
-            mStartSessionResponseObserver.onNext(StartSessionResponse.getDefaultInstance());
-        }
-
-        @Override
-        public void onError(Throwable t) {
-            synchronized (mStartSessionResponseObserver) {
-                mStartSessionResponseObserver.onError(t);
-            }
-            if (mCurrentSessionId != null) {
-                destroySession(mCurrentSessionId);
-            }
-            mCurrentSessionId = null;
-        }
-
-        @Override
-        public void onCompleted() {
-            synchronized (mStartSessionResponseObserver) {
-                mStartSessionResponseObserver.onCompleted();
-            }
-            if (mCurrentSessionId != null) {
-                destroySession(mCurrentSessionId);
-            }
-            mCurrentSessionId = null;
-        }
-    }
-
-    @Override
-    public void sendRequestFulfillment(Request request, StreamObserver<Response> responseObserver) {
-        if (request.getFulfillmentRequest().getFulfillmentsList().isEmpty()) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(
-                                    ERROR_NO_FULFILLMENT_REQUEST)));
-            return;
-        }
-        FulfillmentRequest.Fulfillment selectedFulfillment =
-                request.getFulfillmentRequest().getFulfillments(0);
-        Optional<Capability> capability =
-                mRegisteredCapabilities.stream()
-                        .filter(cap -> selectedFulfillment.getIdentifier().equals(cap.getId()))
-                        .findFirst();
-        if (!capability.isPresent()) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(
-                                    ERROR_NO_ACTION_CAPABILITY)));
-            return;
-        }
-        String sessionId = request.getSessionIdentifier();
-        CapabilitySession currentSession = SessionManager.INSTANCE.getSession(sessionId);
-        if (currentSession == null) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION)));
-            return;
-        }
-        if (currentSession.getStatus() == CapabilitySession.Status.COMPLETED
-                || currentSession.getStatus() == CapabilitySession.Status.DESTROYED) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED)));
-            return;
-        }
-        Futures.addCallback(
-                executeFulfillmentRequest(currentSession, selectedFulfillment),
-                new FutureCallback<FulfillmentResponse>() {
-                    @Override
-                    public void onSuccess(FulfillmentResponse fulfillmentResponse) {
-                        Response.Builder responseBuilder =
-                                convertFulfillmentResponse(fulfillmentResponse, capability.get())
-                                        .toBuilder();
-                        UiCache uiCache = UiSessions.INSTANCE.getUiCacheOrNull(sessionId);
-                        if (uiCache != null && uiCache.hasUnreadUiResponse()) {
-                            responseBuilder.setUiUpdate(UiUpdate.getDefaultInstance());
-                            if (!uiCache.getCachedChangedViewIds().isEmpty()) {
-                                responseBuilder.setCollectionUpdate(
-                                        AppInteractionServiceProto.CollectionUpdate.newBuilder()
-                                                .addAllViewIds(uiCache.getCachedChangedViewIds()));
-                            }
-                            uiCache.resetUnreadUiResponse();
-                        }
-                        respondAndComplete(responseBuilder.build(), responseObserver);
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        Throwable outputThrowable;
-                        if (t instanceof CapabilityExecutionException) {
-                            outputThrowable =
-                                    convertToGrpcException((CapabilityExecutionException) t);
-                        } else if (t instanceof StatusRuntimeException
-                                || t instanceof StatusException) {
-                            outputThrowable = t;
-                        } else {
-                            outputThrowable =
-                                    new StatusRuntimeException(
-                                            Status.INTERNAL.withDescription(
-                                                    t.getMessage()).withCause(t));
-                        }
-                        responseObserver.onError(outputThrowable);
-                        // Assistant will terminate the connection, which will reach
-                        // startUpSession.onError(t) / onCompleted()
-                    }
-                },
-                Runnable::run);
-    }
-
-    @Override
-    public void requestUi(
-            AppInteractionServiceProto.UiRequest req,
-            StreamObserver<AppInteractionServiceProto.UiResponse> responseObserver) {
-        String sessionId = req.getSessionIdentifier();
-        CapabilitySession currentSession = SessionManager.INSTANCE
-                .getSession(sessionId);
-        if (currentSession == null) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION)));
-            return;
-        }
-        if (currentSession.getStatus() == CapabilitySession.Status.COMPLETED) {
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED)));
-            return;
-        }
-        UiCache uiCache = UiSessions.INSTANCE.getUiCacheOrNull(sessionId);
-        if (uiCache == null) {
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)));
-            return;
-        }
-
-        TileLayoutInternal tileLayout = uiCache.getCachedTileLayout();
-        SizeF remoteViewsSize = uiCache.getCachedRemoteViewsSize();
-        RemoteViews remoteViews = uiCache.getCachedRemoteViews();
-        if (tileLayout != null && remoteViews != null) {
-            // TODO(b/272379825): Decide if this is really an invalid state.
-            // both types of UI are present, this is a misused of API. We will treat it as error.
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.INTERNAL.withDescription(ERROR_MULTIPLE_UI_TYPES)));
-            return;
-        }
-        if (tileLayout != null) {
-            respondAndComplete(
-                    AppInteractionServiceProto.UiResponse.newBuilder()
-                            .setTileLayout(tileLayout.toProto())
-                            .build(),
-                    responseObserver);
-            return;
-        }
-        if (remoteViews != null && remoteViewsSize != null) {
-            RemoteViewsOverMetadataInterceptor.setRemoteViews(remoteViews);
-            respondAndComplete(
-                    AppInteractionServiceProto.UiResponse.newBuilder()
-                            .setRemoteViewsInfo(
-                                    RemoteViewsInfo.newBuilder()
-                                            .setWidthDp(remoteViewsSize.getWidth())
-                                            .setHeightDp(remoteViewsSize.getHeight()))
-                            .build(),
-                    responseObserver);
-            return;
-        }
-        destroySession(req.getSessionIdentifier());
-        responseObserver.onError(
-                new StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)));
-    }
-
-    @Override
-    public void requestCollection(
-            CollectionRequest req, StreamObserver<CollectionResponse> responseObserver) {
-        String sessionId = req.getSessionIdentifier();
-        CapabilitySession currentSession = SessionManager.INSTANCE
-                .getSession(sessionId);
-        if (currentSession == null) {
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION)));
-            return;
-        }
-        if (currentSession.getStatus() == CapabilitySession.Status.COMPLETED) {
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED)));
-            return;
-        }
-        UiCache uiCache = UiSessions.INSTANCE.getUiCacheOrNull(sessionId);
-        if (uiCache == null) {
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)));
-            return;
-        }
-        RemoteViewsFactory factory = uiCache.onGetViewFactoryInternal(req.getViewId());
-        if (factory == null) {
-            destroySession(req.getSessionIdentifier());
-            responseObserver.onError(
-                    new StatusRuntimeException(
-                            Status.UNIMPLEMENTED.withDescription(ERROR_NO_COLLECTION_SUPPORT)));
-            return;
-        }
-        switch (req.getRequestDataCase()) {
-            case ON_DESTROY: {
-                requestCollectionOnDestroy(factory, responseObserver);
-                break;
-            }
-            case GET_COUNT: {
-                requestCollectionGetCount(factory, responseObserver);
-                break;
-            }
-            case GET_VIEW_AT: {
-                requestCollectionGetViewAt(factory, responseObserver,
-                        req.getGetViewAt().getPosition());
-                break;
-            }
-
-            case GET_LOADING_VIEW: {
-                requestCollectionGetLoadingView(factory, responseObserver);
-                break;
-            }
-            case GET_VIEW_TYPE_COUNT: {
-                requestCollectionGetViewTypeCount(factory, responseObserver);
-                break;
-            }
-            case GET_ITEM_ID: {
-                requestCollectionGetItemId(factory, responseObserver,
-                        req.getGetItemId().getPosition());
-                break;
-            }
-            case HAS_STABLE_IDS: {
-                requestCollectionHasStableIds(factory, responseObserver);
-                break;
-            }
-            default: {
-                // ignore it
-                Log.d(TAG, "received CollectionRequest with unknown RequestData case.");
-                responseObserver.onCompleted();
-                break;
-            }
-        }
-    }
-
-    @Override
-    public void requestGrounding(
-            GroundingRequest request, StreamObserver<GroundingResponse> responseObserver) {
-        // TODO(b/268265068): Implement grounding API
-    }
-
-    private void requestCollectionOnDestroy(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer) {
-        factory.onDestroy();
-        respondAndComplete(CollectionResponse.getDefaultInstance(), observer);
-    }
-
-    private void requestCollectionGetCount(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer) {
-        respondAndComplete(
-                CollectionResponse.newBuilder()
-                        .setGetCount(CollectionResponse.GetCount.newBuilder()
-                                .setCount(factory.getCount()))
-                        .build(),
-                observer);
-    }
-
-    private void requestCollectionGetViewAt(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer, int position) {
-        RemoteViews view = factory.getViewAt(position);
-        if (view != null) {
-            RemoteViewsOverMetadataInterceptor.setRemoteViews(view);
-        }
-        respondAndComplete(CollectionResponse.getDefaultInstance(), observer);
-    }
-
-    private void requestCollectionGetLoadingView(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer) {
-        RemoteViews loadingView = factory.getLoadingView();
-        if (loadingView != null) {
-            RemoteViewsOverMetadataInterceptor.setRemoteViews(loadingView);
-        }
-        respondAndComplete(CollectionResponse.getDefaultInstance(), observer);
-    }
-
-    private void requestCollectionGetViewTypeCount(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer) {
-        respondAndComplete(
-                CollectionResponse.newBuilder()
-                        .setGetViewTypeCount(
-                                CollectionResponse.GetViewTypeCount.newBuilder()
-                                        .setViewTypeCount(factory.getViewTypeCount()))
-                        .build(),
-                observer);
-    }
-
-    private void requestCollectionGetItemId(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer, int position) {
-        respondAndComplete(
-                CollectionResponse.newBuilder()
-                        .setGetItemId(
-                                CollectionResponse.GetItemId.newBuilder()
-                                        .setItemId(factory.getItemId(position)))
-                        .build(),
-                observer);
-    }
-
-    private void requestCollectionHasStableIds(
-            RemoteViewsFactory factory, StreamObserver<CollectionResponse> observer) {
-        respondAndComplete(
-                CollectionResponse.newBuilder()
-                        .setHasStableIds(
-                                CollectionResponse.HasStableIds.newBuilder()
-                                        .setHasStableIds(factory.hasStableIds()))
-                        .build(),
-                observer);
-    }
-
-    @NonNull
-    private Version convertToAppActionsContextVersion(@NonNull LibInfo.Version libInfoVersion) {
-        Version.Builder builder = Version.newBuilder()
-                .setMajor(libInfoVersion.getMajor())
-                .setMinor(libInfoVersion.getMinor())
-                .setPatch(libInfoVersion.getPatch());
-        if (libInfoVersion.getPreReleaseId() != null) {
-            builder.setPrereleaseId(libInfoVersion.getPreReleaseId());
-        }
-        return builder.build();
-    }
-
-    void destroySession(@NonNull String sessionId) {
-        CapabilitySession session = SessionManager.INSTANCE.getSession(sessionId);
-        if (session != null) {
-            session.destroy();
-        }
-        SessionManager.INSTANCE.removeSession(sessionId);
-    }
-
-    @NonNull
-    StatusRuntimeException convertToGrpcException(CapabilityExecutionException e) {
-        if (e.getErrorStatus() == ErrorStatusInternal.TIMEOUT) {
-            return new StatusRuntimeException(
-                    Status.DEADLINE_EXCEEDED.withDescription(e.getMessage()).withCause(e));
-        }
-        return new StatusRuntimeException(
-                Status.INTERNAL.withDescription(e.getMessage()).withCause(e));
-    }
-
-    @NonNull
-    Response convertFulfillmentResponse(
-            @NonNull FulfillmentResponse fulfillmentResponse,
-            @NonNull Capability capability) {
-        AppActionsContext.AppAction appAction = capability.getAppAction();
-        boolean isDialogSession = appAction.getTaskInfo().getSupportsPartialFulfillment();
-        Version version = convertToAppActionsContextVersion(
-                new LibInfo(mAppInteractionService.getApplicationContext()).getVersion());
-        Response.Builder responseBuilder =
-                // TODO(b/269638788): Add DialogState to the Response proto.
-                Response.newBuilder()
-                        .setFulfillmentResponse(fulfillmentResponse)
-                        .setAppActionsContext(
-                                AppActionsContext.newBuilder()
-                                        .addActions(appAction)
-                                        .setVersion(version)
-                                        .build());
-        if (!isDialogSession) {
-            responseBuilder.setEndingStatus(
-                    AppInteractionServiceProto.Status.newBuilder()
-                            .setStatusCode(Code.COMPLETE)
-                            .build());
-        }
-        return responseBuilder.build();
-    }
-
-    @NonNull
-    ListenableFuture<FulfillmentResponse> executeFulfillmentRequest(
-            @NonNull CapabilitySession session,
-            @NonNull FulfillmentRequest.Fulfillment fulfillmentRequest) {
-        return CallbackToFutureAdapter.getFuture(
-                completer -> {
-                    session.execute(
-                            ArgumentsWrapper.create(fulfillmentRequest),
-                            new CapabilityCallback(completer));
-                    return "executing action capability";
-                });
-    }
-
-    static <T> void respondAndComplete(T response, StreamObserver<T> responseObserver) {
-        responseObserver.onNext(response);
-        responseObserver.onCompleted();
-    }
-}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt
new file mode 100644
index 0000000..8d5f6a5
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImpl.kt
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.service
+
+import android.util.Log
+import android.util.SizeF
+import android.widget.RemoteViewsService.RemoteViewsFactory
+import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.HostProperties
+import androidx.appactions.interaction.capabilities.core.LibInfo
+import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper
+import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
+import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal
+import androidx.appactions.interaction.capabilities.core.impl.concurrent.FutureCallback
+import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures
+import androidx.appactions.interaction.capabilities.core.impl.utils.CapabilityLogger
+import androidx.appactions.interaction.capabilities.core.impl.utils.CapabilityLogger.LogLevel
+import androidx.appactions.interaction.capabilities.core.impl.utils.LoggerInternal
+import androidx.appactions.interaction.proto.AppActionsContext
+import androidx.appactions.interaction.proto.FulfillmentRequest
+import androidx.appactions.interaction.proto.FulfillmentResponse
+import androidx.appactions.interaction.proto.GroundingRequest
+import androidx.appactions.interaction.proto.GroundingResponse
+import androidx.appactions.interaction.proto.Version
+import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc.AppInteractionServiceImplBase
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionRequest.RequestDataCase
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.CollectionResponse
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.RemoteViewsInfo
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Request
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Response
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionRequest
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionResponse
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Status.Code
+import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.UiUpdate
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import com.google.common.util.concurrent.ListenableFuture
+import io.grpc.Status
+import io.grpc.StatusException
+import io.grpc.StatusRuntimeException
+import io.grpc.stub.StreamObserver
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+/**
+ * Implementation of [AppInteractionServiceImplBase] generated from the GRPC proto file. This
+ * class delegates the requests to the appropriate capability session.
+ */
+internal class AppInteractionServiceGrpcImpl(
+    private val appInteractionService: AppInteractionService,
+) : AppInteractionServiceImplBase() {
+
+    var registeredCapabilities = listOf<Capability>()
+
+    companion object {
+        private const val TAG = "ActionsServiceGrpcImpl"
+        private const val ERROR_NO_COLLECTION_SUPPORT = "Session doesn't support collection view"
+        private const val ERROR_NO_UI = "No UI set"
+        private const val ERROR_MULTIPLE_UI_TYPES = "Multiple UI types used in current session"
+        const val ERROR_NO_SESSION = "Session not available"
+        const val ERROR_NO_FULFILLMENT_REQUEST = "Fulfillment request missing"
+        const val ERROR_NO_ACTION_CAPABILITY = "Capability was not found"
+        const val ERROR_SESSION_ENDED = "Session already ended"
+
+        fun <T> respondAndComplete(response: T, responseObserver: StreamObserver<T>) {
+            synchronized(responseObserver) {
+                responseObserver.onNext(response)
+                responseObserver.onCompleted()
+            }
+        }
+
+        fun respondWithError(t: Throwable, responseObserver: StreamObserver<*>) {
+            synchronized(responseObserver) {
+                responseObserver.onError(t)
+            }
+        }
+
+        init {
+            LoggerInternal.setLogger(
+                object : CapabilityLogger {
+                    override fun log(
+                        logLevel: LogLevel,
+                        logTag: String,
+                        message: String,
+                    ) {
+                        when (logLevel) {
+                            LogLevel.ERROR -> Log.e(logTag, message)
+                            LogLevel.WARN -> Log.w(logTag, message)
+                            LogLevel.INFO -> Log.i(logTag, message)
+                        }
+                    }
+
+                    override fun log(
+                        logLevel: LogLevel,
+                        logTag: String,
+                        message: String,
+                        throwable: Throwable,
+                    ) {
+                        when (logLevel) {
+                            LogLevel.ERROR -> Log.e(logTag, message, throwable)
+                            LogLevel.WARN -> Log.w(logTag, message, throwable)
+                            LogLevel.INFO -> Log.i(logTag, message, throwable)
+                        }
+                    }
+                },
+            )
+        }
+    }
+
+    override fun startUpSession(
+        responseObserver: StreamObserver<StartSessionResponse>,
+    ): StreamObserver<StartSessionRequest> = StartSessionRequestObserver(responseObserver)
+
+    private inner class StartSessionRequestObserver internal constructor(
+        private val startSessionResponseObserver: StreamObserver<StartSessionResponse>,
+    ) : StreamObserver<StartSessionRequest> {
+
+        // Every AppInteractionService connection is defined by this streaming RPC connection.
+        // There should only be one session tied to each gRPC impl instance.
+        private var currentSessionId: String? = null
+
+        override fun onNext(request: StartSessionRequest) {
+            if (currentSessionId != null) {
+                return
+            }
+            val sessionId = request.getSessionIdentifier()!!
+            currentSessionId = sessionId
+            if (registeredCapabilities.size == 0) {
+                registeredCapabilities = appInteractionService.registeredCapabilities
+            }
+            val targetCapability = registeredCapabilities
+                .filter { request.getIdentifier() == it.id }
+                .firstOrNull()
+            if (targetCapability == null) {
+                return respondWithError(
+                    StatusRuntimeException(
+                        Status.FAILED_PRECONDITION.withDescription(
+                            ERROR_NO_ACTION_CAPABILITY,
+                        ),
+                    ),
+                    startSessionResponseObserver,
+                )
+            }
+            val hostProperties = HostProperties.Builder()
+                .setMaxHostSizeDp(
+                    SizeF(
+                        request.getHostProperties().getHostViewHeightDp(),
+                        request.getHostProperties().getHostViewWidthDp(),
+                    ),
+                ).build()
+            val session = targetCapability.createSession(
+                sessionId,
+                hostProperties,
+            )
+            SessionManager.putSession(sessionId, session)
+            startSessionResponseObserver.onNext(StartSessionResponse.getDefaultInstance())
+        }
+
+        override fun onError(t: Throwable) {
+            respondWithError(t, startSessionResponseObserver)
+            currentSessionId?.let(::destroySession)
+            currentSessionId = null
+        }
+
+        override fun onCompleted() {
+            synchronized(startSessionResponseObserver) {
+                startSessionResponseObserver.onCompleted()
+            }
+            currentSessionId?.let(::destroySession)
+            currentSessionId = null
+        }
+    }
+
+    override fun sendRequestFulfillment(
+        request: Request,
+        responseObserver: StreamObserver<Response>,
+    ) {
+        if (request.getFulfillmentRequest().getFulfillmentsList().isEmpty()) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(
+                        ERROR_NO_FULFILLMENT_REQUEST,
+                    ),
+                ),
+                responseObserver,
+            )
+        }
+        val selectedFulfillment = request.getFulfillmentRequest().getFulfillments(0)
+        val capability = registeredCapabilities
+            .filter { selectedFulfillment.getIdentifier() == it.id }
+            .firstOrNull()
+        if (capability == null) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(
+                        ERROR_NO_ACTION_CAPABILITY,
+                    ),
+                ),
+                responseObserver,
+            )
+        }
+        val sessionId = request.getSessionIdentifier()!!
+        val currentSession = SessionManager.getSession(sessionId)
+        if (currentSession == null) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+                ),
+                responseObserver,
+            )
+        }
+        if (currentSession.status === CapabilitySession.Status.COMPLETED ||
+            currentSession.status === CapabilitySession.Status.DESTROYED
+        ) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED),
+                ),
+                responseObserver,
+            )
+        }
+        Futures.addCallback(
+            executeFulfillmentRequest(currentSession, selectedFulfillment),
+            object : FutureCallback<FulfillmentResponse> {
+                override fun onSuccess(fulfillmentResponse: FulfillmentResponse) {
+                    val responseBuilder =
+                        convertFulfillmentResponse(fulfillmentResponse, capability)
+                            .toBuilder()
+                    val uiCache = UiSessions.getUiCacheOrNull(sessionId)
+                    if (uiCache != null && uiCache.hasUnreadUiResponse()) {
+                        responseBuilder.setUiUpdate(UiUpdate.getDefaultInstance())
+                        if (!uiCache.getCachedChangedViewIds().isEmpty()) {
+                            responseBuilder.setCollectionUpdate(
+                                AppInteractionServiceProto.CollectionUpdate.newBuilder()
+                                    .addAllViewIds(uiCache.getCachedChangedViewIds()),
+                            )
+                        }
+                        uiCache.resetUnreadUiResponse()
+                    }
+                    respondAndComplete(responseBuilder.build(), responseObserver)
+                }
+
+                override fun onFailure(t: Throwable) {
+                    respondWithError(
+                        when {
+                            t is CapabilityExecutionException -> convertToGrpcException(t)
+                            t is StatusRuntimeException || t is StatusException -> t
+                            else -> StatusRuntimeException(
+                                Status.INTERNAL.withDescription(
+                                    t.message,
+                                ).withCause(t),
+                            )
+                        },
+                        responseObserver,
+                    )
+                    // Assistant will terminate the connection, which will reach
+                    // startUpSession.onError(t) / onCompleted()
+                }
+            },
+            Runnable::run,
+        )
+    }
+
+    override fun requestUi(
+        req: AppInteractionServiceProto.UiRequest,
+        responseObserver: StreamObserver<AppInteractionServiceProto.UiResponse>,
+    ) {
+        val sessionId = req.getSessionIdentifier()!!
+        val currentSession = SessionManager.getSession(sessionId)
+        if (currentSession == null) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+                ),
+                responseObserver,
+            )
+        }
+        if (currentSession.status === CapabilitySession.Status.COMPLETED) {
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED),
+                ),
+                responseObserver,
+            )
+        }
+        val uiCache = UiSessions.getUiCacheOrNull(sessionId)
+        if (uiCache == null) {
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+                responseObserver,
+            )
+        }
+        val tileLayout = uiCache.getCachedTileLayout()
+        val remoteViewsSize = uiCache.getCachedRemoteViewsSize()
+        val remoteViews = uiCache.getCachedRemoteViews()
+        if (tileLayout != null && remoteViews != null) {
+            // TODO(b/272379825): Decide if this is really an invalid state.
+            // both types of UI are present, this is a misused of API. We will treat it as error.
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.INTERNAL.withDescription(ERROR_MULTIPLE_UI_TYPES),
+                ),
+                responseObserver,
+            )
+        }
+        if (tileLayout != null) {
+            return respondAndComplete(
+                AppInteractionServiceProto.UiResponse.newBuilder()
+                    .setTileLayout(tileLayout.toProto())
+                    .build(),
+                responseObserver,
+            )
+        }
+        if (remoteViews != null && remoteViewsSize != null) {
+            RemoteViewsOverMetadataInterceptor.setRemoteViews(remoteViews)
+            return respondAndComplete(
+                AppInteractionServiceProto.UiResponse.newBuilder()
+                    .setRemoteViewsInfo(
+                        RemoteViewsInfo.newBuilder()
+                            .setWidthDp(remoteViewsSize.getWidth())
+                            .setHeightDp(remoteViewsSize.getHeight()),
+                    )
+                    .build(),
+                responseObserver,
+            )
+        }
+        destroySession(req.getSessionIdentifier())
+        respondWithError(
+            StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+            responseObserver,
+        )
+    }
+
+    override fun requestCollection(
+        req: CollectionRequest,
+        responseObserver: StreamObserver<CollectionResponse>,
+    ) {
+        val sessionId = req.getSessionIdentifier()!!
+        val currentSession = SessionManager.getSession(sessionId)
+        if (currentSession == null) {
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_NO_SESSION),
+                ),
+                responseObserver,
+            )
+        }
+        if (currentSession.status === CapabilitySession.Status.COMPLETED) {
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.FAILED_PRECONDITION.withDescription(ERROR_SESSION_ENDED),
+                ),
+                responseObserver,
+            )
+        }
+        val uiCache = UiSessions.getUiCacheOrNull(sessionId)
+        if (uiCache == null) {
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(Status.INTERNAL.withDescription(ERROR_NO_UI)),
+                responseObserver,
+            )
+        }
+        val factory = uiCache.onGetViewFactoryInternal(req.getViewId())
+        if (factory == null) {
+            destroySession(req.getSessionIdentifier())
+            return respondWithError(
+                StatusRuntimeException(
+                    Status.UNIMPLEMENTED.withDescription(ERROR_NO_COLLECTION_SUPPORT),
+                ),
+                responseObserver,
+            )
+        }
+        when (req.getRequestDataCase()) {
+            RequestDataCase.ON_DESTROY -> {
+                requestCollectionOnDestroy(factory, responseObserver)
+            }
+            RequestDataCase.GET_COUNT -> {
+                requestCollectionGetCount(factory, responseObserver)
+            }
+            RequestDataCase.GET_VIEW_AT -> {
+                requestCollectionGetViewAt(
+                    factory,
+                    responseObserver,
+                    req.getGetViewAt().getPosition(),
+                )
+            }
+            RequestDataCase.GET_LOADING_VIEW -> {
+                requestCollectionGetLoadingView(factory, responseObserver)
+            }
+            RequestDataCase.GET_VIEW_TYPE_COUNT -> {
+                requestCollectionGetViewTypeCount(factory, responseObserver)
+            }
+            RequestDataCase.GET_ITEM_ID -> {
+                requestCollectionGetItemId(
+                    factory,
+                    responseObserver,
+                    req.getGetItemId().getPosition(),
+                )
+            }
+            RequestDataCase.HAS_STABLE_IDS -> {
+                requestCollectionHasStableIds(factory, responseObserver)
+            }
+            else -> {
+                // ignore it
+                Log.d(TAG, "received CollectionRequest with unknown RequestData case.")
+                responseObserver.onCompleted()
+            }
+        }
+    }
+
+    override fun requestGrounding(
+        request: GroundingRequest,
+        responseObserver: StreamObserver<GroundingResponse>,
+    ) {
+        val entityProvider = appInteractionService.registeredEntityProviders.filter {
+            it.id == request.getRequest().getEntityProviderId()
+        }.firstOrNull()
+        if (entityProvider == null) {
+            return respondAndComplete(
+                GroundingResponse.newBuilder()
+                    .setResponse(
+                        GroundingResponse.Response.newBuilder().setStatus(
+                            GroundingResponse.Status.INVALID_ENTITY_PROVIDER,
+                        ),
+                    ).build(),
+                responseObserver,
+            )
+        }
+        CoroutineScope(Dispatchers.Unconfined).launch {
+            try {
+                respondAndComplete(
+                    entityProvider.lookupInternal(request),
+                    responseObserver,
+                )
+            } catch (t: Throwable) {
+                respondWithError(
+                    when {
+                        t is StatusRuntimeException || t is StatusException -> t
+                        else -> StatusRuntimeException(
+                            Status.INTERNAL.withDescription(
+                                t.message,
+                            ).withCause(t),
+                        )
+                    },
+                    responseObserver,
+                )
+            }
+        }
+    }
+
+    private fun requestCollectionOnDestroy(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+    ) {
+        factory.onDestroy()
+        respondAndComplete(CollectionResponse.getDefaultInstance(), observer)
+    }
+
+    private fun requestCollectionGetCount(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+    ) {
+        respondAndComplete(
+            CollectionResponse.newBuilder()
+                .setGetCount(
+                    CollectionResponse.GetCount.newBuilder()
+                        .setCount(factory.getCount()),
+                )
+                .build(),
+            observer,
+        )
+    }
+
+    private fun requestCollectionGetViewAt(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+        position: Int,
+    ) {
+        factory.getViewAt(position)?.let(RemoteViewsOverMetadataInterceptor::setRemoteViews)
+        respondAndComplete(CollectionResponse.getDefaultInstance(), observer)
+    }
+
+    private fun requestCollectionGetLoadingView(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+    ) {
+        factory.getLoadingView()?.let(RemoteViewsOverMetadataInterceptor::setRemoteViews)
+        respondAndComplete(CollectionResponse.getDefaultInstance(), observer)
+    }
+
+    private fun requestCollectionGetViewTypeCount(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+    ) {
+        respondAndComplete(
+            CollectionResponse.newBuilder()
+                .setGetViewTypeCount(
+                    CollectionResponse.GetViewTypeCount.newBuilder()
+                        .setViewTypeCount(factory.getViewTypeCount()),
+                )
+                .build(),
+            observer,
+        )
+    }
+
+    private fun requestCollectionGetItemId(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+        position: Int,
+    ) {
+        respondAndComplete(
+            CollectionResponse.newBuilder()
+                .setGetItemId(
+                    CollectionResponse.GetItemId.newBuilder()
+                        .setItemId(factory.getItemId(position)),
+                )
+                .build(),
+            observer,
+        )
+    }
+
+    private fun requestCollectionHasStableIds(
+        factory: RemoteViewsFactory,
+        observer: StreamObserver<CollectionResponse>,
+    ) {
+        respondAndComplete(
+            CollectionResponse.newBuilder()
+                .setHasStableIds(
+                    CollectionResponse.HasStableIds.newBuilder()
+                        .setHasStableIds(factory.hasStableIds()),
+                )
+                .build(),
+            observer,
+        )
+    }
+
+    private fun convertToAppActionsContextVersion(
+        libInfoVersion: LibInfo.Version,
+    ): Version {
+        val builder = Version.newBuilder()
+            .setMajor(libInfoVersion.major.toLong())
+            .setMinor(libInfoVersion.minor.toLong())
+            .setPatch(libInfoVersion.patch.toLong())
+        libInfoVersion.preReleaseId?.let(builder::setPrereleaseId)
+        return builder.build()
+    }
+
+    private fun destroySession(sessionId: String) {
+        SessionManager.getSession(sessionId)?.destroy()
+        SessionManager.removeSession(sessionId)
+    }
+
+    internal fun convertToGrpcException(e: CapabilityExecutionException): StatusRuntimeException {
+        return when (e.getErrorStatus()) {
+            ErrorStatusInternal.TIMEOUT -> StatusRuntimeException(
+                Status.DEADLINE_EXCEEDED.withDescription(e.message).withCause(e),
+            )
+            else -> StatusRuntimeException(
+                Status.INTERNAL.withDescription(e.message).withCause(e),
+            )
+        }
+    }
+
+    internal fun convertFulfillmentResponse(
+        fulfillmentResponse: FulfillmentResponse,
+        capability: Capability,
+    ): Response {
+        val appAction = capability.appAction
+        val isDialogSession = appAction.getTaskInfo().getSupportsPartialFulfillment()
+        val version = convertToAppActionsContextVersion(
+            LibInfo(appInteractionService.getApplicationContext()).getVersion(),
+        )
+        val responseBuilder: Response.Builder =
+            // TODO(b/269638788): Add DialogState to the Response proto.
+            Response.newBuilder()
+                .setFulfillmentResponse(fulfillmentResponse)
+                .setAppActionsContext(
+                    AppActionsContext.newBuilder()
+                        .addActions(appAction)
+                        .setVersion(version)
+                        .build(),
+                )
+        if (!isDialogSession) {
+            responseBuilder.setEndingStatus(
+                AppInteractionServiceProto.Status.newBuilder()
+                    .setStatusCode(Code.COMPLETE)
+                    .build(),
+            )
+        }
+        return responseBuilder.build()
+    }
+
+    private fun executeFulfillmentRequest(
+        session: CapabilitySession,
+        fulfillmentRequest: FulfillmentRequest.Fulfillment,
+    ): ListenableFuture<FulfillmentResponse> = CallbackToFutureAdapter.getFuture { completer ->
+        session.execute(
+            ArgumentsWrapper.create(fulfillmentRequest),
+            CapabilityCallback(completer),
+        )
+        "executing action capability"
+    }
+}
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiCache.java b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiCache.java
index 5683769..e0f8353 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiCache.java
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiCache.java
@@ -22,7 +22,7 @@
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
-import androidx.appactions.interaction.capabilities.core.BaseSession;
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -65,7 +65,7 @@
     private boolean mUnreadUiResponse;
 
     /**
-     * Caches a UiResponse for this particular {@link BaseSession}.
+     * Caches a UiResponse for this particular {@link BaseExecutionSession}.
      */
     public void updateUiInternal(@NonNull UiResponse uiResponse) {
         synchronized (mLock) {
diff --git a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiSessions.kt b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiSessions.kt
index 7621aee..2366e49 100644
--- a/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiSessions.kt
+++ b/appactions/interaction/interaction-service/src/main/java/androidx/appactions/interaction/service/UiSessions.kt
@@ -19,7 +19,7 @@
 
 import androidx.annotation.GuardedBy
 import androidx.appactions.interaction.capabilities.core.ActionExecutor
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.impl.UiHandleRegistry
 import androidx.appactions.interaction.service.UiSessions.removeUiCache
 import javax.annotation.concurrent.ThreadSafe
@@ -64,8 +64,8 @@
     }
 }
 
-/** Return a UI associated with this [BaseSession]. */
-fun BaseSession<*, *>.updateUi(uiResponse: UiResponse) =
+/** Return a UI associated with this [BaseExecutionSession]. */
+fun BaseExecutionSession<*, *>.updateUi(uiResponse: UiResponse) =
     UiSessions.getOrCreateUiCache(
         UiHandleRegistry.getSessionIdFromUiHandle(this)!!
     ).updateUiInternal(uiResponse)
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt
new file mode 100644
index 0000000..6f339d4
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceEntityProviderTest.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.service
+
+import androidx.appactions.interaction.capabilities.core.impl.converters.EntityConverter
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
+import androidx.appactions.interaction.capabilities.core.values.Alarm
+import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils.buildSearchActionParamValue
+import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.awaitSync
+import androidx.appactions.interaction.proto.GroundingRequest
+import androidx.appactions.interaction.proto.GroundingRequest.Request
+import androidx.appactions.interaction.proto.GroundingResponse
+import androidx.appactions.interaction.proto.GroundingResponse.Candidate
+import androidx.appactions.interaction.proto.GroundingResponse.Response
+import androidx.appactions.interaction.proto.GroundingResponse.Status
+import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc
+import androidx.appactions.interaction.service.testing.internal.FakeAlarmEntityProvider
+import androidx.appactions.interaction.service.testing.internal.FakeAppInteractionService
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import io.grpc.BindableService
+import io.grpc.ManagedChannel
+import io.grpc.Server
+import io.grpc.inprocess.InProcessChannelBuilder
+import io.grpc.inprocess.InProcessServerBuilder
+import io.grpc.stub.StreamObserver
+import io.grpc.testing.GrpcCleanupRule
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.times
+import org.robolectric.Robolectric
+
+// TODO(b/271929200) Implement tests for the 2 UI related RPCs
+@RunWith(AndroidJUnit4::class)
+class AppInteractionServiceEntityProviderTest {
+    val testServerName = "testServer"
+
+    @get:Rule val grpcCleanup = GrpcCleanupRule()
+
+    private lateinit var appInteractionService: FakeAppInteractionService
+
+    @Before
+    fun before() {
+        appInteractionService = Robolectric.buildService(
+            FakeAppInteractionService::class.java
+        ).get()
+    }
+
+    @Test
+    fun alarmProvider_incorrectProviderId(): Unit = runBlocking {
+        val morningAlarm = Alarm.newBuilder().setId("alarm1").setName("Morning Alarm").build()
+        val alarmProvider = FakeAlarmEntityProvider(
+            "alarmProvider",
+            listOf(morningAlarm)
+        )
+        appInteractionService.registeredEntityProviders = listOf(alarmProvider)
+        val server =
+            createInProcessServer(
+                AppInteractionServiceGrpcImpl(appInteractionService)
+            )
+
+        val channel = createInProcessChannel()
+        val stub = AppInteractionServiceGrpc.newStub(channel)
+
+        val groundingRequest = GroundingRequest
+            .newBuilder()
+            .setRequest(
+                Request.newBuilder()
+                    .setEntityProviderId("randomIncorrectId")
+                    .setSearchAction(
+                        buildSearchActionParamValue(
+                            "alarm search query"
+                        )
+                    )
+            )
+            .build()
+
+        val responseObserver = TestStreamObserver<GroundingResponse>()
+        stub.requestGrounding(groundingRequest, responseObserver)
+        val groundingResponse = responseObserver.firstResultDeferred.awaitSync()
+        assertThat(groundingResponse).isEqualTo(
+            GroundingResponse.newBuilder()
+            .setResponse(
+                GroundingResponse.Response.newBuilder().setStatus(
+                    GroundingResponse.Status.INVALID_ENTITY_PROVIDER,
+                ),
+            ).build()
+        )
+
+        server.shutdownNow()
+    }
+
+    @Test
+    fun alarmProvider_success(): Unit = runBlocking {
+        val morningAlarm = Alarm.newBuilder().setId("alarm1").setName("Morning Alarm").build()
+        val alarmProvider = FakeAlarmEntityProvider(
+            "alarmProvider",
+            listOf(morningAlarm)
+        )
+        appInteractionService.registeredEntityProviders = listOf(alarmProvider)
+        val server =
+            createInProcessServer(
+                AppInteractionServiceGrpcImpl(appInteractionService)
+            )
+
+        val channel = createInProcessChannel()
+        val stub = AppInteractionServiceGrpc.newStub(channel)
+
+        val groundingRequest = GroundingRequest
+            .newBuilder()
+            .setRequest(
+                Request.newBuilder()
+                    .setEntityProviderId("alarmProvider")
+                    .setSearchAction(
+                        buildSearchActionParamValue(
+                            "alarm search query"
+                        )
+                    )
+            )
+            .build()
+
+        val responseObserver = TestStreamObserver<GroundingResponse>()
+        stub.requestGrounding(groundingRequest, responseObserver)
+        val groundingResponse = responseObserver.firstResultDeferred.awaitSync()
+        assertThat(groundingResponse).isEqualTo(
+            GroundingResponse.newBuilder().setResponse(
+                Response.newBuilder()
+                    .setStatus(Status.SUCCESS)
+                    .addCandidates(
+                        Candidate.newBuilder().setGroundedEntity(
+                            EntityConverter.of(TypeConverters.ALARM_TYPE_SPEC).convert(morningAlarm)
+                        )
+                    )
+            ).build()
+        )
+
+        server.shutdownNow()
+    }
+
+    private fun createInProcessServer(
+        service: BindableService
+    ): Server {
+        return grpcCleanup.register(
+            InProcessServerBuilder.forName(testServerName)
+                .directExecutor()
+                .addService(service)
+                .build()
+                .start()
+        )
+    }
+
+    private fun createInProcessChannel(): ManagedChannel {
+        return grpcCleanup.register(
+            InProcessChannelBuilder.forName(testServerName).directExecutor().build()
+        )
+    }
+
+    /** Captures the first error or value received by the stream observer */
+    private class TestStreamObserver<T> : StreamObserver<T> {
+        val firstResultDeferred = CompletableDeferred<T>()
+
+        override fun onNext(value: T) {
+            firstResultDeferred.complete(value)
+        }
+
+        override fun onError(t: Throwable) {
+            firstResultDeferred.completeExceptionally(t)
+        }
+
+        override fun onCompleted() {
+            firstResultDeferred.cancel()
+        }
+    }
+}
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
index b466a6e..e9b80f9 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/AppInteractionServiceGrpcImplTest.kt
@@ -16,7 +16,6 @@
 
 package androidx.appactions.interaction.service
 
-import android.content.Context
 import androidx.appactions.interaction.capabilities.core.Capability
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal
@@ -27,17 +26,17 @@
 import androidx.appactions.interaction.proto.FulfillmentResponse
 import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput
 import androidx.appactions.interaction.proto.FulfillmentResponse.StructuredOutput.OutputValue
-import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.ERROR_NO_ACTION_CAPABILITY
-import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.ERROR_NO_FULFILLMENT_REQUEST
-import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.ERROR_NO_SESSION
-import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.ERROR_SESSION_ENDED
+import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.Companion.ERROR_NO_ACTION_CAPABILITY
+import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.Companion.ERROR_NO_FULFILLMENT_REQUEST
+import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.Companion.ERROR_NO_SESSION
+import androidx.appactions.interaction.service.AppInteractionServiceGrpcImpl.Companion.ERROR_SESSION_ENDED
+import androidx.appactions.interaction.service.testing.internal.FakeAppInteractionService
 import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc
 import androidx.appactions.interaction.service.proto.AppInteractionServiceGrpc.AppInteractionServiceStub
 import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.Request
 import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionRequest
 import androidx.appactions.interaction.service.proto.AppInteractionServiceProto.StartSessionResponse
 import androidx.concurrent.futures.await
-import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
 import org.mockito.kotlin.any
@@ -48,6 +47,7 @@
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
+import org.robolectric.Robolectric
 import io.grpc.BindableService
 import io.grpc.ManagedChannel
 import io.grpc.Server
@@ -55,14 +55,11 @@
 import io.grpc.ServerInterceptors
 import io.grpc.Status
 import io.grpc.StatusRuntimeException
-import io.grpc.binder.SecurityPolicies
-import io.grpc.binder.SecurityPolicy
 import io.grpc.inprocess.InProcessChannelBuilder
 import io.grpc.inprocess.InProcessServerBuilder
 import io.grpc.stub.StreamObserver
 import io.grpc.testing.GrpcCleanupRule
 import java.io.IOException
-import java.util.Collections
 import kotlin.test.assertFailsWith
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.runBlocking
@@ -77,7 +74,6 @@
 
     @get:Rule val grpcCleanup = GrpcCleanupRule()
 
-    private val context = ApplicationProvider.getApplicationContext<Context>()
     private val remoteViewsInterceptor: ServerInterceptor = RemoteViewsOverMetadataInterceptor()
     private val testServerName = InProcessServerBuilder.generateName()
     private val testBiiName = "actions.intent.SAMPLE_BII_NAME"
@@ -102,22 +98,27 @@
                     .addOutputValues(OutputValue.newBuilder().setName("bio_arg1")),
             )
             .build()
-    private var capability1 = mock<Capability>()
+    private lateinit var capability1: Capability
+    private lateinit var appInteractionService: FakeAppInteractionService
 
     @Before
     fun before() {
         capability1 = mock()
         whenever(capability1.id).thenReturn(capabilityId)
-        whenever(capability1.getAppAction()).thenReturn(AppAction.getDefaultInstance())
+        whenever(capability1.appAction).thenReturn(AppAction.getDefaultInstance())
         val mockCapabilitySession = createMockSession()
         whenever(capability1.createSession(any(), any())).thenReturn(mockCapabilitySession)
+        appInteractionService = Robolectric.buildService(
+            FakeAppInteractionService::class.java
+        ).get()
+        appInteractionService.registeredCapabilities = listOf(capability1)
     }
 
     @Test
     fun startUpSession_validRequest_shouldGetValidStartSessionResponse(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -152,7 +153,7 @@
     fun startUpSession_shouldFailWhenNoStaticCapability(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -186,7 +187,7 @@
     fun sendRequestFulfillment_shouldGetValidResponse(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
         val channel = createInProcessChannel()
@@ -213,7 +214,7 @@
     fun sendRequestFulfillment_shouldFailWhenNoFulfillment(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -243,7 +244,7 @@
     fun sendRequestFulfillment_shouldFailWhenNoStaticCapability(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -278,7 +279,7 @@
     fun sendRequestFulfillment_shouldFailWhenNoSession(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -310,7 +311,7 @@
     fun sendRequestFulfillment_shouldFailWhenSessionEnded(): Unit = runBlocking {
         val server =
             createInProcessServer(
-                AppInteractionServiceGrpcImpl(FakeAppInteractionService(listOf(capability1))),
+                AppInteractionServiceGrpcImpl(appInteractionService),
                 remoteViewsInterceptor,
             )
 
@@ -395,18 +396,4 @@
         whenever(mockSession.uiHandle).thenReturn(Any())
         return mockSession
     }
-
-    private inner class FakeAppInteractionService(capabilities: List<Capability>) :
-        AppInteractionService() {
-        override val registeredCapabilities: MutableList<Capability> =
-            capabilities.toMutableList()
-
-        override val securityPolicy: SecurityPolicy = SecurityPolicies.internalOnly()
-
-        override val allowedApps: List<AppVerificationInfo> = Collections.emptyList()
-
-        override fun getApplicationContext(): Context {
-            return context
-        }
-    }
 }
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiCacheTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiCacheTest.kt
index 4cf3bbe..9d9056c 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiCacheTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiCacheTest.kt
@@ -19,7 +19,7 @@
 import android.content.Context
 import android.util.SizeF
 import android.widget.RemoteViews
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.service.test.R
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -29,7 +29,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class UiCacheTest {
-    private val capabilitySession = object : BaseSession<String, String> {}
+    private val capabilitySession = object : BaseExecutionSession<String, String> {}
     private val context: Context = ApplicationProvider.getApplicationContext()
     private val remoteViewsFactoryId = 123
     private val changeViewId = 111
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiSessionsTest.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiSessionsTest.kt
index 8e38923..16ec377 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiSessionsTest.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/UiSessionsTest.kt
@@ -22,7 +22,7 @@
 import androidx.appactions.interaction.capabilities.core.ActionExecutor
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.HostProperties
-import androidx.appactions.interaction.capabilities.core.SessionFactory
+import androidx.appactions.interaction.capabilities.core.ExecutionSessionFactory
 import androidx.appactions.interaction.proto.FulfillmentRequest.Fulfillment.Type.SYNC
 import androidx.appactions.interaction.proto.ParamValue
 import androidx.appactions.interaction.service.test.R
@@ -31,9 +31,9 @@
 import androidx.appactions.interaction.capabilities.testing.internal.ArgumentUtils.buildArgs
 import androidx.appactions.interaction.capabilities.testing.internal.TestingUtils.CB_TIMEOUT
 import androidx.appactions.interaction.service.testing.internal.FakeCapability
-import androidx.appactions.interaction.service.testing.internal.FakeCapability.Argument
+import androidx.appactions.interaction.service.testing.internal.FakeCapability.Arguments
 import androidx.appactions.interaction.service.testing.internal.FakeCapability.Output
-import androidx.appactions.interaction.service.testing.internal.FakeCapability.Session
+import androidx.appactions.interaction.service.testing.internal.FakeCapability.ExecutionSession
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.wear.tiles.LayoutElementBuilders
@@ -45,16 +45,16 @@
 
 @RunWith(AndroidJUnit4::class)
 class UiSessionsTest {
-    private val sessionFactory = object : SessionFactory<Session> {
-        private val sessions = mutableListOf<Session>()
+    private val sessionFactory = object : ExecutionSessionFactory<ExecutionSession> {
+        private val sessions = mutableListOf<ExecutionSession>()
         private var index = 0
         override fun createSession(
             hostProperties: HostProperties?,
-        ): Session {
+        ): ExecutionSession {
             return sessions[index++]
         }
 
-        fun addSessions(vararg session: Session) {
+        fun addExecutionSessions(vararg session: ExecutionSession) {
             sessions.addAll(session)
         }
 
@@ -68,7 +68,7 @@
         HostProperties.Builder().setMaxHostSizeDp(SizeF(300f, 500f)).build()
     private val multiTurnCapability = FakeCapability.CapabilityBuilder()
         .setId("multiTurnCapability")
-        .setSessionFactory(sessionFactory).build()
+        .setExecutionSessionFactory(sessionFactory).build()
 
     private val context: Context = ApplicationProvider.getApplicationContext()
     private val remoteViewsFactoryId = 123
@@ -104,15 +104,15 @@
         UiSessions.removeUiCache(sessionId)
     }
 
-    fun createFakeSessionWithUiResponses(vararg uiResponses: UiResponse): Session {
-        return object : Session {
-            override suspend fun onFinish(
-                argument: Argument,
+    fun createFakeSessionWithUiResponses(vararg uiResponses: UiResponse): ExecutionSession {
+        return object : ExecutionSession {
+            override suspend fun onExecute(
+                arguments: Arguments,
             ): ExecutionResult<Output> {
                 for (uiResponse in uiResponses) {
                     this.updateUi(uiResponse)
                 }
-                return ExecutionResult.getDefaultInstance()
+                return ExecutionResult.Builder<Output>().build()
             }
         }
     }
@@ -121,7 +121,7 @@
     fun sessionExtensionMethod_createCache_removeCache() {
         assertThat(UiSessions.getUiCacheOrNull(sessionId)).isNull()
 
-        sessionFactory.addSessions(
+        sessionFactory.addExecutionSessions(
             createFakeSessionWithUiResponses(remoteViewsUiResponse),
         )
         val session = multiTurnCapability.createSession(sessionId, hostProperties)
@@ -150,14 +150,14 @@
     @Test
     fun multipleUpdate_sharesCache() {
         assertThat(UiSessions.getUiCacheOrNull(sessionId)).isNull()
-        sessionFactory.addSessions(object : Session {
-            override suspend fun onFinish(
-                argument: Argument,
+        sessionFactory.addExecutionSessions(object : ExecutionSession {
+            override suspend fun onExecute(
+                arguments: Arguments,
             ): ExecutionResult<Output> {
                 this.updateUi(remoteViewsUiResponse)
                 this.updateUi(tileLayoutUiResponse)
 
-                return ExecutionResult.getDefaultInstance()
+                return ExecutionResult.Builder<Output>().build()
             }
         })
         val session = multiTurnCapability.createSession(sessionId, hostProperties)
@@ -184,21 +184,21 @@
     fun multipleSession_haveTheirOwnCache() {
         val sessionId1 = "fakeSessionId1"
         val sessionId2 = "fakeSessionId2"
-        sessionFactory.addSessions(
-            object : Session {
-                override suspend fun onFinish(
-                    argument: Argument,
+        sessionFactory.addExecutionSessions(
+            object : ExecutionSession {
+                override suspend fun onExecute(
+                    arguments: Arguments,
                 ): ExecutionResult<Output> {
                     this.updateUi(remoteViewsUiResponse)
-                    return ExecutionResult.getDefaultInstance()
+                    return ExecutionResult.Builder<Output>().build()
                 }
             },
-            object : Session {
-                override suspend fun onFinish(
-                    argument: Argument,
+            object : ExecutionSession {
+                override suspend fun onExecute(
+                    arguments: Arguments,
                 ): ExecutionResult<Output> {
                     this.updateUi(tileLayoutUiResponse)
-                    return ExecutionResult.getDefaultInstance()
+                    return ExecutionResult.Builder<Output>().build()
                 }
             },
         )
@@ -253,10 +253,10 @@
         assertThat(UiSessions.getUiCacheOrNull(sessionId)).isNull()
         val oneShotCapability = FakeCapability.CapabilityBuilder().setId(
             "oneShotCapability",
-        ).setExecutor(object : ActionExecutor<Argument, Output> {
-            override suspend fun execute(argument: Argument): ExecutionResult<Output> {
+        ).setExecutor(object : ActionExecutor<Arguments, Output> {
+            override suspend fun onExecute(arguments: Arguments): ExecutionResult<Output> {
                 this.updateUi(remoteViewsUiResponse)
-                return ExecutionResult.getDefaultInstance()
+                return ExecutionResult.Builder<Output>().build()
             }
         }).build()
         val session = oneShotCapability.createSession(
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt
new file mode 100644
index 0000000..c2b23b1
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAlarmEntityProvider.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.service.testing.internal
+
+import androidx.appactions.interaction.capabilities.core.entity.EntityProvider
+import androidx.appactions.interaction.capabilities.core.entity.EntityLookupRequest
+import androidx.appactions.interaction.capabilities.core.entity.EntityLookupResponse
+import androidx.appactions.interaction.capabilities.core.entity.EntityLookupCandidate
+import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
+import androidx.appactions.interaction.capabilities.core.values.Alarm
+
+class FakeAlarmEntityProvider(
+    override val id: String,
+    private val alarms: List<Alarm> = listOf()
+) : EntityProvider<Alarm>(
+    TypeConverters.ALARM_TYPE_SPEC
+) {
+    override suspend fun lookup(
+        request: EntityLookupRequest<Alarm>
+    ): EntityLookupResponse<Alarm> {
+        return EntityLookupResponse.Builder<Alarm>().setCandidateList(
+            alarms.map { EntityLookupCandidate.Builder<Alarm>().setCandidate(it).build() }
+        ).setStatus(
+            EntityLookupResponse.SUCCESS
+        ).build()
+    }
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAppInteractionService.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAppInteractionService.kt
new file mode 100644
index 0000000..9521309
--- /dev/null
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeAppInteractionService.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appactions.interaction.service.testing.internal
+
+import androidx.appactions.interaction.service.AppInteractionService
+import androidx.appactions.interaction.service.AppVerificationInfo
+import androidx.appactions.interaction.capabilities.core.Capability
+import androidx.appactions.interaction.capabilities.core.entity.EntityProvider
+import io.grpc.binder.SecurityPolicies
+import io.grpc.binder.SecurityPolicy
+
+class FakeAppInteractionService() : AppInteractionService() {
+    override var registeredCapabilities: List<Capability> = listOf()
+    override var registeredEntityProviders: List<EntityProvider<*>> = listOf()
+    override val securityPolicy: SecurityPolicy = SecurityPolicies.internalOnly()
+    override val allowedApps: List<AppVerificationInfo> = listOf()
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
index 116f73b..fce9017 100644
--- a/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
+++ b/appactions/interaction/interaction-service/src/test/java/androidx/appactions/interaction/service/testing/internal/FakeCapability.kt
@@ -17,47 +17,44 @@
 package androidx.appactions.interaction.service.testing.internal
 
 import androidx.appactions.interaction.capabilities.core.Capability
-import androidx.appactions.interaction.capabilities.core.BaseSession
-import androidx.appactions.interaction.capabilities.core.CapabilityBuilderBase
-import androidx.appactions.interaction.capabilities.core.SessionFactory
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
+import androidx.appactions.interaction.capabilities.core.ExecutionSessionFactory
 import androidx.appactions.interaction.capabilities.core.ValueListener
 import androidx.appactions.interaction.capabilities.core.impl.BuilderOf
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters
 import androidx.appactions.interaction.capabilities.core.impl.spec.ActionSpecBuilder
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
-import androidx.appactions.interaction.capabilities.core.properties.TypeProperty
-import androidx.appactions.interaction.capabilities.core.impl.task.AbstractTaskUpdater
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.impl.task.SessionBridge
 import androidx.appactions.interaction.capabilities.core.impl.task.TaskHandler
 import java.util.Optional
-import java.util.function.Supplier
 
 private const val CAPABILITY_NAME = "actions.intent.FAKE_CAPABILITY"
 private val ACTION_SPEC = ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-    .setDescriptor(FakeCapability.Property::class.java)
-    .setArgument(FakeCapability.Argument::class.java, FakeCapability.Argument::Builder)
+    .setDescriptor(FakeCapability.Properties::class.java)
+    .setArguments(FakeCapability.Arguments::class.java, FakeCapability.Arguments::Builder)
     .setOutput(FakeCapability.Output::class.java).bindOptionalParameter(
         "fieldOne",
         { property -> Optional.ofNullable(property.fieldOne) },
-        FakeCapability.Argument.Builder::setFieldOne,
+        FakeCapability.Arguments.Builder::setFieldOne,
         TypeConverters.STRING_PARAM_VALUE_CONVERTER,
         TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
     ).build()
 
 class FakeCapability private constructor() {
-    class Property(
-        val fieldOne: TypeProperty<StringValue>? = null,
+    class Properties(
+        val fieldOne: Property<StringValue>? = null,
     )
 
-    class Argument internal constructor(
+    class Arguments internal constructor(
         val fieldOne: String?,
     ) {
-        class Builder : BuilderOf<Argument> {
+        class Builder : BuilderOf<Arguments> {
             private var fieldOne: String? = null
             fun setFieldOne(value: String) = apply {
                 fieldOne = value
             }
-            override fun build() = Argument(fieldOne)
+            override fun build() = Arguments(fieldOne)
         }
     }
 
@@ -65,23 +62,20 @@
 
     class Confirmation internal constructor()
 
-    interface Session : BaseSession<Argument, Output> {
+    interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
         val fieldOneListener: ValueListener<String>?
             get() = null
     }
 
-    class SessionUpdater internal constructor() : AbstractTaskUpdater()
-
-    class CapabilityBuilder : CapabilityBuilderBase<
+    class CapabilityBuilder : Capability.Builder<
         CapabilityBuilder,
-        Property,
-        Argument,
+        Properties,
+        Arguments,
         Output,
         Confirmation,
-        SessionUpdater,
-        Session,
+        ExecutionSession,
         >(ACTION_SPEC) {
-        override val sessionBridge = SessionBridge<Session, Confirmation> {
+        override val sessionBridge = SessionBridge<ExecutionSession, Confirmation> {
                 session ->
             val builder = TaskHandler.Builder<Confirmation>()
             session.fieldOneListener?.let {
@@ -94,20 +88,18 @@
             builder.build()
         }
 
-        override val sessionUpdaterSupplier = Supplier { SessionUpdater() }
+        private var fieldOne: Property<StringValue>? = null
 
-        private var fieldOne: TypeProperty<StringValue>? = null
-
-        fun setFieldOne(fieldOne: TypeProperty<StringValue>) = apply {
+        fun setFieldOne(fieldOne: Property<StringValue>) = apply {
             this.fieldOne = fieldOne
         }
 
-        public override fun setSessionFactory(
-            sessionFactory: SessionFactory<Session>,
-        ) = super.setSessionFactory(sessionFactory)
+        public override fun setExecutionSessionFactory(
+            sessionFactory: ExecutionSessionFactory<ExecutionSession>,
+        ) = super.setExecutionSessionFactory(sessionFactory)
 
         override fun build(): Capability {
-            super.setProperty(Property(fieldOne))
+            super.setProperty(Properties(fieldOne))
             return super.build()
         }
     }
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
index 6ed63ee..1ee50ec 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/GlobalSearchSessionImpl.java
@@ -86,7 +86,7 @@
     public ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentIdAsync(
             @NonNull String packageName, @NonNull String databaseName,
             @NonNull GetByDocumentIdRequest request) {
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             throw new UnsupportedOperationException(Features.GLOBAL_SEARCH_SESSION_GET_BY_ID
                     + " is not supported on this AppSearch implementation.");
         }
@@ -138,7 +138,7 @@
             @NonNull String databaseName) {
         // Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
         // unsupported build.
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             throw new UnsupportedOperationException(
                     Features.GLOBAL_SEARCH_SESSION_GET_SCHEMA
                             + " is not supported on this AppSearch implementation.");
@@ -176,7 +176,7 @@
         Preconditions.checkNotNull(observer);
         // Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
         // unsupported build.
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             throw new UnsupportedOperationException(
                     Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK
                             + " is not supported on this AppSearch implementation");
@@ -239,7 +239,7 @@
         Preconditions.checkNotNull(observer);
         // Superclass is annotated with @RequiresFeature, so we shouldn't get here on an
         // unsupported build.
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             throw new UnsupportedOperationException(
                     Features.GLOBAL_SEARCH_SESSION_REGISTER_OBSERVER_CALLBACK
                             + " is not supported on this AppSearch implementation");
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
index a4621c2..4e4f3db 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/SearchSessionImpl.java
@@ -209,7 +209,7 @@
                     + "JoinSpec was provided.");
         }
 
-        if (!BuildCompat.isAtLeastT() && !searchSpec.getFilterNamespaces().isEmpty()) {
+        if (Build.VERSION.SDK_INT < 33 && !searchSpec.getFilterNamespaces().isEmpty()) {
             // This is a patch for b/197361770, framework-appsearch in Android S will
             // disable the given namespace filter if it is not empty and none of given namespaces
             // exist.
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
index b69caca..05575ce 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/GetSchemaResponseToPlatformConverter.java
@@ -49,7 +49,7 @@
             @NonNull android.app.appsearch.GetSchemaResponse platformResponse) {
         Preconditions.checkNotNull(platformResponse);
         GetSchemaResponse.Builder jetpackBuilder;
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             // Android API level in S-v2 and lower won't have any supported feature.
             jetpackBuilder = new GetSchemaResponse.Builder(/*getVisibilitySettingSupported=*/false);
         } else {
diff --git a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
index 6950427..48c3ede 100644
--- a/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
+++ b/appsearch/appsearch-platform-storage/src/main/java/androidx/appsearch/platformstorage/converter/SetSchemaRequestToPlatformConverter.java
@@ -74,7 +74,7 @@
             }
         }
         if (!jetpackRequest.getRequiredPermissionsForSchemaTypeVisibility().isEmpty()) {
-            if (!BuildCompat.isAtLeastT()) {
+            if (Build.VERSION.SDK_INT < 33) {
                 throw new UnsupportedOperationException(
                         "Set required permissions for schema type visibility are not supported "
                                 + "with this backend/Android API level combination.");
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
index 866b963..aba266a 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/AppSearchSessionLocalCtsTest.java
@@ -16,6 +16,8 @@
 // @exportToFramework:skipFile()
 package androidx.appsearch.cts.app;
 
+import static android.os.Build.VERSION.SDK_INT;
+
 import static androidx.appsearch.testutil.AppSearchTestUtils.checkIsBatchResultSuccess;
 import static androidx.appsearch.testutil.AppSearchTestUtils.convertSearchResultsToDocuments;
 import static androidx.appsearch.testutil.AppSearchTestUtils.doGet;
@@ -23,6 +25,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.os.Build;
 
 import androidx.annotation.NonNull;
 import androidx.appsearch.app.AppSearchBatchResult;
@@ -48,6 +51,7 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import org.junit.Assume;
 import org.junit.Test;
 
 import java.util.Arrays;
@@ -486,9 +490,15 @@
                 .isEqualTo(SchemaMigrationStats.SECOND_CALL_APPLY_NEW_SCHEMA);
     }
 
+    private void maybeSkipLargeDocumentTest() {
+        // Skip running this test on emulators API 26 - 28 b/269806908
+        Assume.assumeTrue(!(Build.MODEL.contains("SDK") && SDK_INT >= 26 && SDK_INT < 29));
+    }
+
     // Framework has max Document size which is 512KiB, this test should only exists in Jetpack.
     @Test
     public void testPutLargeDocumentToIcing() throws Exception {
+        maybeSkipLargeDocumentTest();
         Context context = ApplicationProvider.getApplicationContext();
         AppSearchSession db2 = LocalStorage.createSearchSessionAsync(
                 new LocalStorage.SearchContext.Builder(context, DB_NAME_2).build()).get();
@@ -524,6 +534,7 @@
     // Framework has max Document size which is 512KiB, this test should only exists in Jetpack.
     @Test
     public void testPutLargeDocumentToIcing_exceedLimit() throws Exception {
+        maybeSkipLargeDocumentTest();
         Context context = ApplicationProvider.getApplicationContext();
         AppSearchSession db2 = LocalStorage.createSearchSessionAsync(
                 new LocalStorage.SearchContext.Builder(context, DB_NAME_2).build()).get();
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
index f4ec042..995c84d 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
@@ -89,6 +89,13 @@
         productFlavors = null
     )
 
+    private val Variant.benchmarkVariantName: String
+        get() {
+            val parts = listOfNotNull(flavorName, BUILD_TYPE_BENCHMARK_PREFIX, buildType)
+                .filter { it.isNotBlank() }
+            return camelCase(*parts.toTypedArray())
+        }
+
     override fun onAgpPluginNotFound(pluginIds: Set<AgpPluginId>) {
         throw IllegalStateException(
             """
@@ -387,13 +394,13 @@
             mergeTaskProvider
         }
 
-        // Here we create the final generate task that triggers the whole generation
-        // for this variant and all the parent tasks. For this one the child task
-        // is either copy or merge, depending on the configuration.
-        val variantGenerateTask = maybeCreateGenerateTask<Task>(
+        // Here we create the final generate task that triggers the whole generation for this
+        // variant and all the parent tasks. For this one the child task is either copy or merge,
+        // depending on the configuration.
+        maybeCreateGenerateTask<Task>(
             project = project,
             variantName = mergeAwareVariantName,
-            childGenerationTaskProvider = lastTaskProvider
+            lastTaskProvider = lastTaskProvider
         )
 
         // Create the build type task. For example `generateReleaseBaselineProfile`
@@ -401,37 +408,53 @@
         // Note that if `mergeIntoMain` is `true` the build type task already exists.
         if (!mergeIntoMain &&
             !variant.buildType.isNullOrBlank() &&
-            variant.name != variant.buildType
+            variant.buildType != variant.name
         ) {
             maybeCreateGenerateTask<Task>(
                 project = project,
                 variantName = variant.buildType!!,
-                childGenerationTaskProvider = variantGenerateTask
+                lastTaskProvider = lastTaskProvider
             )
         }
 
-        // TODO: Due to b/265438201 we cannot have a global task
-        //  `generateBaselineProfile` that triggers generation for all the
-        //  variants when there are multiple build types. The temporary workaround
-        //  is to generate baseline profiles only for variants with the `release`
-        //  build type until that bug is fixed, when running the global task
-        //  `generateBaselineProfile`. This can be removed after fix.
-        if (variant.buildType == RELEASE) {
-            maybeCreateGenerateTask<MainGenerateBaselineProfileTask>(
-                project,
-                "",
-                variantGenerateTask
+        if (supportsFeature(AgpFeature.TEST_MODULE_SUPPORTS_MULTIPLE_BUILD_TYPES)) {
+
+            // Generate a flavor task, such as `generateFreeBaselineProfile`
+            if (!mergeIntoMain &&
+                !variant.flavorName.isNullOrBlank() &&
+                variant.flavorName != variant.name
+            ) {
+                maybeCreateGenerateTask<Task>(
+                    project = project,
+                    variantName = variant.flavorName!!,
+                    lastTaskProvider = lastTaskProvider
+                )
+            }
+
+            // Generate the main global tasks `generateBaselineProfile
+            maybeCreateGenerateTask<Task>(
+                project = project,
+                variantName = "",
+                lastTaskProvider = lastTaskProvider
             )
+        } else {
+            // Due to b/265438201 we cannot have a global task `generateBaselineProfile` that
+            // triggers generation for all the variants when there are multiple build types.
+            // So for version of AGP that don't support that, invoking `generateBaselineProfile`
+            // will run generation for `release` build type only, that is the same behavior of
+            // `generateReleaseBaselineProfile`. For this same reason we cannot have a flavor
+            // task, such as `generateFreeBaselineProfile` because that would run generation for
+            // all the build types with flavor free, that is not as well supported.
+            if (variant.buildType == RELEASE) {
+                maybeCreateGenerateTask<MainGenerateBaselineProfileTask>(
+                    project = project,
+                    variantName = "",
+                    lastTaskProvider = lastTaskProvider
+                )
+            }
         }
     }
 
-    private val Variant.benchmarkVariantName: String
-        get() {
-            val parts = listOfNotNull(flavorName, BUILD_TYPE_BENCHMARK_PREFIX, buildType)
-                .filter { it.isNotBlank() }
-            return camelCase(*parts.toTypedArray())
-        }
-
     private fun createConfigurationForVariant(
         variant: Variant,
         mainConfiguration: Configuration?,
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/GenerateBaselineProfileTask.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/GenerateBaselineProfileTask.kt
index 422ba51..0bed7c1 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/GenerateBaselineProfileTask.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/GenerateBaselineProfileTask.kt
@@ -34,11 +34,11 @@
 internal inline fun <reified T : Task> maybeCreateGenerateTask(
     project: Project,
     variantName: String,
-    childGenerationTaskProvider: TaskProvider<*>? = null
+    lastTaskProvider: TaskProvider<*>? = null
 ) = project.tasks.maybeRegister<T>(GENERATE_TASK_NAME, variantName, TASK_NAME_SUFFIX) {
     it.group = "Baseline Profile"
     it.description = "Generates a baseline profile for the specified variants or dimensions."
-    if (childGenerationTaskProvider != null) it.dependsOn(childGenerationTaskProvider)
+    if (lastTaskProvider != null) it.dependsOn(lastTaskProvider)
 }
 
 @DisableCachingByDefault(because = "Not worth caching.")
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
index ecb6ba3..69455db 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
@@ -21,13 +21,15 @@
 import androidx.baselineprofile.gradle.utils.ANDROID_TEST_PLUGIN
 import androidx.baselineprofile.gradle.utils.BaselineProfileProjectSetupRule
 import androidx.baselineprofile.gradle.utils.Fixtures
+import androidx.baselineprofile.gradle.utils.TEST_AGP_VERSION_8_0_0
 import androidx.baselineprofile.gradle.utils.TEST_AGP_VERSION_8_1_0
 import androidx.baselineprofile.gradle.utils.TEST_AGP_VERSION_ALL
 import androidx.baselineprofile.gradle.utils.VariantProfile
 import androidx.baselineprofile.gradle.utils.build
 import androidx.baselineprofile.gradle.utils.buildAndAssertThatOutput
+import androidx.baselineprofile.gradle.utils.require
+import androidx.baselineprofile.gradle.utils.requireInOrder
 import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
 import java.io.File
 import org.junit.Rule
 import org.junit.Test
@@ -61,6 +63,11 @@
         "src/$variantName/$EXPECTED_PROFILE_FOLDER/startup-prof.txt"
     )
 
+    private fun mergedArtProfile(variantName: String) = File(
+        projectSetup.consumer.rootDir,
+        "build/intermediates/merged_art_profile/$variantName/baseline-prof.txt"
+    )
+
     private fun readBaselineProfileFileContent(variantName: String): List<String> =
         baselineProfileFile(variantName).readLines()
 
@@ -378,9 +385,10 @@
             .build()
 
         // In the final output there should be :
-        //  - one single file in src/main/generatedBaselineProfiles because merge = `all`.
+        //  - one single file in src/main/generated/baselineProfiles (because this is a library).
         //  - There should be only the Utils class [CLASS_2] because of the include filter.
-        //  - The method `someOtherMethod` [CLASS_2_METHOD_3] should be included only once.
+        //  - The method `someOtherMethod` [CLASS_2_METHOD_3] should be included only once
+        //      (despite being included multiple times with different flags).
         assertThat(readBaselineProfileFileContent("main"))
             .containsExactly(
                 Fixtures.CLASS_2,
@@ -391,6 +399,66 @@
     }
 
     @Test
+    fun testFilterPerVariant() {
+        projectSetup.consumer.setup(
+            androidPlugin = ANDROID_APPLICATION_PLUGIN,
+            flavors = true,
+            baselineProfileBlock = """
+                filter {
+                    include("com.sample.Activity")
+                }
+                variants {
+                    freeRelease {
+                        filter { include("com.sample.Utils") }
+                    }
+                    paidRelease {
+                        filter { include("com.sample.Fragment") }
+                    }
+                }
+            """.trimIndent()
+        )
+
+        val commonProfile = listOf(
+            Fixtures.CLASS_1,
+            Fixtures.CLASS_1_METHOD_1,
+            Fixtures.CLASS_1_METHOD_2,
+            Fixtures.CLASS_2,
+            Fixtures.CLASS_2_METHOD_1,
+            Fixtures.CLASS_2_METHOD_2,
+            Fixtures.CLASS_2_METHOD_3,
+            Fixtures.CLASS_3,
+            Fixtures.CLASS_3_METHOD_1,
+        )
+        projectSetup.producer.setupWithFreeAndPaidFlavors(
+            freeReleaseProfileLines = commonProfile,
+            paidReleaseProfileLines = commonProfile,
+        )
+
+        gradleRunner
+            .withArguments("generateBaselineProfile", "--stacktrace")
+            .build()
+
+        assertThat(readBaselineProfileFileContent("freeRelease"))
+            .containsExactly(
+                Fixtures.CLASS_1,
+                Fixtures.CLASS_1_METHOD_1,
+                Fixtures.CLASS_1_METHOD_2,
+                Fixtures.CLASS_2,
+                Fixtures.CLASS_2_METHOD_1,
+                Fixtures.CLASS_2_METHOD_2,
+                Fixtures.CLASS_2_METHOD_3,
+            )
+        assertThat(readBaselineProfileFileContent("paidRelease"))
+            .containsExactly(
+                Fixtures.CLASS_1,
+                Fixtures.CLASS_1_METHOD_1,
+                Fixtures.CLASS_1_METHOD_2,
+                Fixtures.CLASS_3,
+                Fixtures.CLASS_3_METHOD_1,
+            )
+    }
+
+    @Test
     fun testSaveInSrcTrueAndAutomaticGenerationDuringBuildTrue() {
         projectSetup.consumer.setup(
             androidPlugin = ANDROID_APPLICATION_PLUGIN,
@@ -406,14 +474,15 @@
         )
 
         // Asserts that assembling release triggers generation of profile
-        gradleRunner.buildAndAssertThatOutput("assembleFreeRelease", "--dry-run") {
-            arrayOf(
-                "mergeFreeReleaseBaselineProfile",
-                "copyFreeReleaseBaselineProfileIntoSrc",
-                "mergeFreeReleaseArtProfile",
-                "compileFreeReleaseArtProfile",
-                "assembleFreeRelease"
-            ).forEach { contains(":${projectSetup.consumer.name}:$it") }
+        gradleRunner.build("assembleFreeRelease", "--dry-run") {
+            val notFound = it.lines().requireInOrder(
+                ":${projectSetup.consumer.name}:mergeFreeReleaseBaselineProfile",
+                ":${projectSetup.consumer.name}:copyFreeReleaseBaselineProfileIntoSrc",
+                ":${projectSetup.consumer.name}:mergeFreeReleaseArtProfile",
+                ":${projectSetup.consumer.name}:compileFreeReleaseArtProfile",
+                ":${projectSetup.consumer.name}:assembleFreeRelease"
+            )
+            assertThat(notFound).isEmpty()
         }
 
         // Asserts that the profile is generated in the src folder
@@ -891,6 +960,128 @@
             )
         )
     }
+
+    @Test
+    fun testBaselineProfileIsInMergeArtProfileIntermediate() {
+        projectSetup.consumer.setup(
+            androidPlugin = ANDROID_APPLICATION_PLUGIN,
+            flavors = true,
+            baselineProfileBlock = """
+                saveInSrc = true
+                automaticGenerationDuringBuild = true
+            """.trimIndent()
+        )
+
+        data class VariantAndProfile(val variantName: String, val profile: List<String>)
+
+        val freeRelease = VariantAndProfile(
+            variantName = "freeRelease",
+            profile = listOf(
+                Fixtures.CLASS_1,
+                Fixtures.CLASS_1_METHOD_1,
+                Fixtures.CLASS_1_METHOD_2,
+                Fixtures.CLASS_3,
+                Fixtures.CLASS_3_METHOD_1,
+            )
+        )
+        val paidRelease = VariantAndProfile(
+            variantName = "paidRelease",
+            profile = listOf(
+                Fixtures.CLASS_1,
+                Fixtures.CLASS_1_METHOD_1,
+                Fixtures.CLASS_1_METHOD_2,
+                Fixtures.CLASS_2,
+                Fixtures.CLASS_2_METHOD_1,
+                Fixtures.CLASS_2_METHOD_2,
+                Fixtures.CLASS_2_METHOD_3,
+            )
+        )
+        projectSetup.producer.setupWithFreeAndPaidFlavors(
+            freeReleaseProfileLines = freeRelease.profile,
+            paidReleaseProfileLines = paidRelease.profile,
+        )
+
+        gradleRunner
+            .build("mergeFreeReleaseArtProfile", "mergePaidReleaseArtProfile") {}
+
+        arrayOf(freeRelease, paidRelease).forEach {
+            val notFound = mergedArtProfile(it.variantName)
+                .readLines()
+                .require(*(it.profile).toTypedArray())
+            assertThat(notFound).isEmpty()
+        }
+    }
+}
+
+@RunWith(JUnit4::class)
+class BaselineProfileConsumerPluginTestWithAgp80 {
+
+    @get:Rule
+    val projectSetup = BaselineProfileProjectSetupRule(
+        forceAgpVersion = TEST_AGP_VERSION_8_0_0
+    )
+
+    @Test
+    fun verifyGenerateTasks() {
+        projectSetup.producer.setupWithFreeAndPaidFlavors(
+            freeReleaseProfileLines = listOf(Fixtures.CLASS_1_METHOD_1, Fixtures.CLASS_1),
+            paidReleaseProfileLines = listOf(Fixtures.CLASS_2_METHOD_1, Fixtures.CLASS_2),
+            freeAnotherReleaseProfileLines = listOf(Fixtures.CLASS_3_METHOD_1, Fixtures.CLASS_3),
+            paidAnotherReleaseProfileLines = listOf(Fixtures.CLASS_4_METHOD_1, Fixtures.CLASS_4),
+        )
+        projectSetup.consumer.setup(
+            androidPlugin = ANDROID_APPLICATION_PLUGIN,
+            dependencyOnProducerProject = true,
+            flavors = true,
+            buildTypeAnotherRelease = true
+        )
+        projectSetup.consumer.gradleRunner.build("tasks") {
+
+            val notFound = it.lines().require(
+                "generateBaselineProfile - ",
+                "generateReleaseBaselineProfile - ",
+                "generateAnotherReleaseBaselineProfile - ",
+                "generateFreeReleaseBaselineProfile - ",
+                "generatePaidReleaseBaselineProfile - ",
+                "generateFreeAnotherReleaseBaselineProfile - ",
+                "generatePaidAnotherReleaseBaselineProfile - ",
+            )
+            assertThat(notFound).isEmpty()
+
+            // Note that there are no flavor tasks with AGP 8.0 because it would build across
+            // multiple build types.
+            assertThat(it).apply {
+                doesNotContain("generateFreeBaselineProfile")
+                doesNotContain("generatePaidBaselineProfile")
+            }
+        }
+
+        val name = projectSetup.consumer.name
+
+        // 'generateBaselineProfile` does the same of `generateReleaseBaselineProfile`.
+        arrayOf(
+            "generateBaselineProfile",
+            "generateReleaseBaselineProfile"
+        ).forEach { cmd ->
+            projectSetup.consumer.gradleRunner.build(cmd, "--dry-run") {
+                val notFound = it.lines().require(
+                    ":$name:copyFreeReleaseBaselineProfileIntoSrc",
+                    ":$name:copyPaidReleaseBaselineProfileIntoSrc",
+                )
+                assertThat(notFound).isEmpty()
+            }
+        }
+
+        projectSetup.consumer.gradleRunner.build(
+            "generateAnotherReleaseBaselineProfile", "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyFreeAnotherReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidAnotherReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+    }
 }
 
 @RunWith(JUnit4::class)
@@ -902,6 +1093,91 @@
     )
 
     @Test
+    fun verifyGenerateTasks() {
+        projectSetup.producer.setupWithFreeAndPaidFlavors(
+            freeReleaseProfileLines = listOf(Fixtures.CLASS_1_METHOD_1, Fixtures.CLASS_1),
+            paidReleaseProfileLines = listOf(Fixtures.CLASS_2_METHOD_1, Fixtures.CLASS_2),
+            freeAnotherReleaseProfileLines = listOf(Fixtures.CLASS_3_METHOD_1, Fixtures.CLASS_3),
+            paidAnotherReleaseProfileLines = listOf(Fixtures.CLASS_4_METHOD_1, Fixtures.CLASS_4),
+        )
+        projectSetup.consumer.setup(
+            androidPlugin = ANDROID_APPLICATION_PLUGIN,
+            dependencyOnProducerProject = true,
+            flavors = true,
+            buildTypeAnotherRelease = true
+        )
+        projectSetup.consumer.gradleRunner.build("tasks") {
+            val notFound = it.lines().require(
+                "generateBaselineProfile - ",
+                "generateReleaseBaselineProfile - ",
+                "generateAnotherReleaseBaselineProfile - ",
+                "generateFreeBaselineProfile - ",
+                "generatePaidBaselineProfile - ",
+                "generateFreeReleaseBaselineProfile - ",
+                "generatePaidReleaseBaselineProfile - ",
+                "generateFreeAnotherReleaseBaselineProfile - ",
+                "generatePaidAnotherReleaseBaselineProfile - ",
+            )
+            assertThat(notFound).isEmpty()
+        }
+
+        val name = projectSetup.consumer.name
+
+        projectSetup.consumer.gradleRunner.build(
+            "generateBaselineProfile", "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyFreeReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidReleaseBaselineProfileIntoSrc",
+                ":$name:copyFreeAnotherReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidAnotherReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+
+        projectSetup.consumer.gradleRunner.build(
+            "generateReleaseBaselineProfile", "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyFreeReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+
+        projectSetup.consumer.gradleRunner.build(
+            "generateAnotherReleaseBaselineProfile",
+            "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyFreeAnotherReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidAnotherReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+
+        projectSetup.consumer.gradleRunner.build(
+            "generateFreeBaselineProfile", "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyFreeReleaseBaselineProfileIntoSrc",
+                ":$name:copyFreeAnotherReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+
+        projectSetup.consumer.gradleRunner.build(
+            "generatePaidBaselineProfile", "--dry-run"
+        ) {
+            val notFound = it.lines().require(
+                ":$name:copyPaidReleaseBaselineProfileIntoSrc",
+                ":$name:copyPaidAnotherReleaseBaselineProfileIntoSrc",
+            )
+            assertThat(notFound).isEmpty()
+        }
+    }
+
+    @Test
     fun verifyTasksWithAndroidTestPlugin() {
         projectSetup.consumer.setup(
             androidPlugin = ANDROID_APPLICATION_PLUGIN,
@@ -935,7 +1211,7 @@
                 val consumerName = projectSetup.consumer.name
                 val producerName = projectSetup.producer.name
 
-                val tasksToFindInOrder = mutableSetOf(
+                val notFound = text.lines().requireInOrder(
                     ":$consumerName:packageFreeNonMinifiedRelease",
                     ":$producerName:connectedFreeNonMinifiedReleaseAndroidTest",
                     ":$producerName:collectFreeNonMinifiedReleaseBaselineProfile",
@@ -948,19 +1224,7 @@
                     ":$producerName:connectedFreeBenchmarkReleaseAndroidTest"
                 )
 
-                text.lines().forEach {
-                    val next = tasksToFindInOrder.firstOrNull() ?: return@forEach
-                    if (it.startsWith(next)) tasksToFindInOrder.remove(next)
-                }
-
-                assertWithMessage(
-                    """
-                `connectedFreeBenchmarkReleaseAndroidTest` did not trigger all the expected tasks.
-                Missing tasks:
-                ${tasksToFindInOrder.joinToString("\n") { "\t\t\t\t$it" }}
-
-                """.trimIndent()
-                ).that(tasksToFindInOrder).isEmpty()
+                assertThat(notFound).isEmpty()
             }
     }
 }
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
index fcc87ae..e3abee6 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/producer/BaselineProfileProducerPluginTest.kt
@@ -21,8 +21,10 @@
 import androidx.baselineprofile.gradle.utils.TEST_AGP_VERSION_8_1_0
 import androidx.baselineprofile.gradle.utils.TEST_AGP_VERSION_ALL
 import androidx.baselineprofile.gradle.utils.VariantProfile
-import androidx.baselineprofile.gradle.utils.buildAndAssertThatOutput
+import androidx.baselineprofile.gradle.utils.build
 import androidx.baselineprofile.gradle.utils.buildAndFailAndAssertThatOutput
+import androidx.baselineprofile.gradle.utils.require
+import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,9 +53,12 @@
             targetProject = projectSetup.appTarget
         )
 
-        projectSetup.producer.gradleRunner.buildAndAssertThatOutput("tasks") {
-            contains("connectedNonMinifiedReleaseAndroidTest - ")
-            contains("collectNonMinifiedReleaseBaselineProfile - ")
+        projectSetup.producer.gradleRunner.build("tasks") {
+            val notFound = it.lines().require(
+                "connectedNonMinifiedReleaseAndroidTest - ",
+                "collectNonMinifiedReleaseBaselineProfile - "
+            )
+            assertThat(notFound).isEmpty()
         }
     }
 }
@@ -80,10 +85,13 @@
             targetProject = projectSetup.appTarget
         )
 
-        projectSetup.producer.gradleRunner.buildAndAssertThatOutput("tasks") {
-            contains("connectedNonMinifiedReleaseAndroidTest - ")
-            contains("connectedBenchmarkReleaseAndroidTest - ")
-            contains("collectNonMinifiedReleaseBaselineProfile - ")
+        projectSetup.producer.gradleRunner.build("tasks") {
+            val notFound = it.lines().require(
+                "connectedNonMinifiedReleaseAndroidTest - ",
+                "connectedBenchmarkReleaseAndroidTest - ",
+                "collectNonMinifiedReleaseBaselineProfile - "
+            )
+            assertThat(notFound).isEmpty()
         }
     }
 }
@@ -138,22 +146,19 @@
         projectSetup
             .producer
             .gradleRunner
-            .buildAndAssertThatOutput(
+            .build(
                 "collectNonMinifiedReleaseBaselineProfile",
                 "--dry-run"
             ) {
-                contains(
-                    ":${projectSetup.appTarget.name}:packageNonMinifiedRelease"
+                val appTargetName = projectSetup.appTarget.name
+                val producerName = projectSetup.producer.name
+                val notFound = it.lines().require(
+                    ":$appTargetName:packageNonMinifiedRelease",
+                    ":$producerName:somePixelDeviceNonMinifiedReleaseAndroidTest",
+                    ":$producerName:connectedNonMinifiedReleaseAndroidTest",
+                    ":$producerName:collectNonMinifiedReleaseBaselineProfile"
                 )
-                contains(
-                    ":${projectSetup.producer.name}:somePixelDeviceNonMinifiedReleaseAndroidTest"
-                )
-                contains(
-                    ":${projectSetup.producer.name}:connectedNonMinifiedReleaseAndroidTest"
-                )
-                contains(
-                    ":${projectSetup.producer.name}:collectNonMinifiedReleaseBaselineProfile"
-                )
+                assertThat(notFound).isEmpty()
             }
     }
 }
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
index 6d15fb46..c4385c0 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/BaselineProfileProjectSetupRule.kt
@@ -17,7 +17,6 @@
 package androidx.baselineprofile.gradle.utils
 
 import androidx.testutils.gradle.ProjectSetupRule
-import com.android.build.api.AndroidPluginVersion
 import com.google.testing.platform.proto.api.core.LabelProto
 import com.google.testing.platform.proto.api.core.PathProto
 import com.google.testing.platform.proto.api.core.TestArtifactProto
@@ -115,9 +114,13 @@
             rootFolder.newFile("gradle.properties").writer().use {
                 val props = Properties()
                 props.setProperty(
-                    "org.gradle.jvmargs", "-Xmx2g -XX:+UseParallelGC -XX:MaxMetaspaceSize=512m"
+                    "org.gradle.jvmargs",
+                    "-Xmx4g -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g"
                 )
-                props.setProperty("android.useAndroidX", "true")
+                props.setProperty(
+                    "android.useAndroidX",
+                    "true"
+                )
                 props.store(it, null)
             }
 
@@ -180,15 +183,6 @@
             base.evaluate()
         }
     }
-
-    private fun AndroidPluginVersion.versionString(): String {
-        val preview = if (!previewType.isNullOrBlank()) {
-            "-$previewType${"%02d".format(preview)}"
-        } else {
-            ""
-        }
-        return "$major.$minor.$micro$preview"
-    }
 }
 
 data class VariantProfile(
@@ -246,27 +240,65 @@
 ) : Module {
 
     fun setupWithFreeAndPaidFlavors(
-        freeReleaseProfileLines: List<String>,
-        paidReleaseProfileLines: List<String>,
+        freeReleaseProfileLines: List<String>? = null,
+        paidReleaseProfileLines: List<String>? = null,
+        freeAnotherReleaseProfileLines: List<String>? = null,
+        paidAnotherReleaseProfileLines: List<String>? = null,
         freeReleaseStartupProfileLines: List<String> = listOf(),
         paidReleaseStartupProfileLines: List<String> = listOf(),
+        freeAnotherReleaseStartupProfileLines: List<String> = listOf(),
+        paidAnotherReleaseStartupProfileLines: List<String> = listOf(),
     ) {
-        setup(
-            variantProfiles = listOf(
-                VariantProfile(
-                    flavor = "free",
-                    buildType = "release",
-                    profileFileLines = mapOf("myTest" to freeReleaseProfileLines),
-                    startupFileLines = mapOf("myStartupTest" to freeReleaseStartupProfileLines)
-                ),
-                VariantProfile(
-                    flavor = "paid",
-                    buildType = "release",
-                    profileFileLines = mapOf("myTest" to paidReleaseProfileLines),
-                    startupFileLines = mapOf("myStartupTest" to paidReleaseStartupProfileLines)
-                ),
-            )
+        val variantProfiles = mutableListOf<VariantProfile>()
+
+        fun addProfile(
+            flavor: String,
+            buildType: String,
+            profile: List<String>?,
+            startupProfile: List<String>,
+        ) {
+            if (profile != null) {
+                variantProfiles.add(
+                    VariantProfile(
+                        flavor = flavor,
+                        buildType = buildType,
+                        profileFileLines = mapOf(
+                            "my-$flavor-$buildType-profile" to profile
+                        ),
+                        startupFileLines = mapOf(
+                            "my-$flavor-$buildType-startup=profile" to startupProfile
+                        )
+                    )
+                )
+            }
+        }
+
+        addProfile(
+            flavor = "free",
+            buildType = "release",
+            profile = freeReleaseProfileLines,
+            startupProfile = freeReleaseStartupProfileLines
         )
+        addProfile(
+            flavor = "free",
+            buildType = "anotherRelease",
+            profile = freeAnotherReleaseProfileLines,
+            startupProfile = freeAnotherReleaseStartupProfileLines
+        )
+        addProfile(
+            flavor = "paid",
+            buildType = "release",
+            profile = paidReleaseProfileLines,
+            startupProfile = paidReleaseStartupProfileLines
+        )
+        addProfile(
+            flavor = "paid",
+            buildType = "anotherRelease",
+            profile = paidAnotherReleaseProfileLines,
+            startupProfile = paidAnotherReleaseStartupProfileLines
+        )
+
+        setup(variantProfiles)
     }
 
     fun setupWithoutFlavors(
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
index 8d29b74..50c69a9 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/utils/TestUtils.kt
@@ -65,3 +65,33 @@
 ) {
     this.buildAndFail(*arguments) { assertBlock(assertThat(it)) }
 }
+
+internal fun List<String>.requireInOrder(
+    vararg strings: String,
+    evaluate: (String, String) -> (Boolean) = { line, nextToFind -> line.startsWith(nextToFind) },
+): List<String> {
+    val remaining = mutableListOf(*strings)
+    for (string in strings) {
+        val next = remaining.firstOrNull() ?: break
+        if (evaluate(string, next)) remaining.remove(next)
+    }
+    return remaining
+}
+
+internal fun List<String>.require(
+    vararg strings: String,
+    evaluate: (String, String) -> (Boolean) = { line, nextToFind -> line.startsWith(nextToFind) },
+): Set<String> {
+    val remaining = mutableSetOf(*strings)
+    for (string in strings) {
+        if (remaining.isEmpty()) break
+        val iter = remaining.iterator()
+        while (iter.hasNext()) iter.next().run {
+            if (evaluate(string, this)) {
+                iter.remove()
+                return@run
+            }
+        }
+    }
+    return remaining
+}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ProfileInstallBroadcastTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ProfileInstallBroadcastTest.kt
index 055ccfd..6398e36 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ProfileInstallBroadcastTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/ProfileInstallBroadcastTest.kt
@@ -19,10 +19,13 @@
 import android.os.Build
 import androidx.benchmark.junit4.PerfettoTraceRule
 import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
+import androidx.core.os.BuildCompat
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import kotlin.test.assertNull
+import org.junit.Assume
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -34,6 +37,12 @@
     @get:Rule
     val perfettoTraceRule = PerfettoTraceRule()
 
+    @Before
+    fun setUp() {
+        // TODO: to re-enable for api 34 (b/276970167)
+        Assume.assumeTrue(!BuildCompat.isAtLeastU())
+    }
+
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
     @Test
     fun installProfile() {
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
index 232202d..ac15ffe 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
@@ -47,7 +47,7 @@
 import org.junit.runners.Parameterized
 import org.junit.runners.Parameterized.Parameters
 
-private const val tracingPerfettoVersion = "1.0.0-alpha14" // TODO(224510255): get by 'reflection'
+private const val tracingPerfettoVersion = "1.0.0-alpha15" // TODO(224510255): get by 'reflection'
 private const val minSupportedSdk = Build.VERSION_CODES.R // TODO(234351579): Support API < 30
 
 @RunWith(Parameterized::class)
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
index e41a947..d839e8f 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
@@ -27,6 +27,7 @@
 import androidx.benchmark.Outputs
 import androidx.benchmark.Shell
 import androidx.benchmark.userspaceTrace
+import androidx.core.os.BuildCompat
 import java.io.File
 
 /**
@@ -147,7 +148,8 @@
                     // Don't reset for subsequent iterations
                     Log.d(TAG, "Killing package $packageName")
                     killProcessBlock()
-                    mode.compileImpl(packageName = packageName,
+                    mode.compileImpl(
+                        packageName = packageName,
                         killProcessBlock = killProcessBlock
                     ) {
                         scope.iteration = iteration
@@ -172,7 +174,8 @@
                 lastProfile = unfilteredProfile
                 stableCount = 1
             } else {
-                Log.d(TAG,
+                Log.d(
+                    TAG,
                     "Profiles stable in iteration $iteration (for $stableCount iterations)"
                 )
                 stableCount += 1
@@ -295,10 +298,22 @@
  * Does not require root.
  */
 @RequiresApi(33)
[email protected](BuildCompat.PrereleaseSdkCheck::class)
 private fun extractProfile(packageName: String): String {
-    Shell.executeScriptSilent(
-        "pm dump-profiles --dump-classes-and-methods $packageName"
-    )
+
+    val dumpCommand = "pm dump-profiles --dump-classes-and-methods $packageName"
+    if (BuildCompat.isAtLeastU()) {
+        // On api 34 this will produce an output like:
+        // Profile saved to '/data/misc/profman/<PACKAGE_NAME>-primary.prof.txt'
+        val stdout = Shell.executeScriptCaptureStdout(dumpCommand).trim()
+        val expected = "Profile saved to '/data/misc/profman/$packageName-primary.prof.txt'"
+        check(stdout == expected) {
+            "Expected `pm dump-profiles` stdout to be $expected but was $stdout"
+        }
+    } else {
+        // On api 33 and below this command does not produce any output
+        Shell.executeScriptSilent(dumpCommand)
+    }
     val fileName = "$packageName-primary.prof.txt"
     Shell.executeScriptSilent(
         "mv /data/misc/profman/$fileName ${Outputs.dirUsableByAppAndShell}/"
diff --git a/benchmark/integration-tests/baselineprofile-consumer/build.gradle b/benchmark/integration-tests/baselineprofile-consumer/build.gradle
index c9b6fbc..64258f7 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-consumer/build.gradle
@@ -1,3 +1,5 @@
+import com.android.build.api.artifact.SingleArtifact
+
 /*
  * Copyright 2022 The Android Open Source Project
  *
@@ -35,14 +37,11 @@
 dependencies {
     implementation(libs.kotlinStdlib)
     implementation(libs.constraintLayout)
+    implementation(project(":profileinstaller:profileinstaller"))
     baselineProfile(project(":benchmark:integration-tests:baselineprofile-producer"))
 }
 
 baselineProfile {
-    filter {
-        include "androidx.benchmark.integration.baselineprofile.consumer.**"
-    }
-
     // Note that these are the default settings, just reported here to make it explicit.
     // `automaticGenerationDuringBuild` has to be off otherwise assembling release on CI would
     // trigger baseline profile generation and integration tests on device.
@@ -51,3 +50,25 @@
 }
 
 apply(from: "../baselineprofile-test-utils/utils.gradle")
+
+// Exposes the apk for profile verifier tests. When calling this function, the generated apks
+// can be utilized with `profileinstaller:integration-tests:profile-verification`.
+configurations {
+    apkAssets {
+        canBeConsumed = true
+        canBeResolved = false
+        attributes {
+            attribute(
+                    LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
+                    objects.named(LibraryElements, 'profileverification-apkAssets')
+            )
+        }
+    }
+}
+androidComponents {
+    onVariants(selector().all().withBuildType("release"), { variant ->
+        artifacts {
+            apkAssets(variant.artifacts.get(SingleArtifact.APK.INSTANCE))
+        }
+    })
+}
diff --git a/benchmark/integration-tests/baselineprofile-consumer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofile-consumer/src/main/AndroidManifest.xml
index b05fc1c..8a03752 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/src/main/AndroidManifest.xml
+++ b/benchmark/integration-tests/baselineprofile-consumer/src/main/AndroidManifest.xml
@@ -20,7 +20,6 @@
         android:allowBackup="false"
         android:label="Jetpack Baselineprofiles Target"
         android:supportsRtl="true"
-        android:theme="@style/Theme.AppCompat"
         tools:ignore="MissingApplicationIcon">
 
         <activity
diff --git a/benchmark/integration-tests/baselineprofile-consumer/src/main/java/androidx/benchmark/integration/baselineprofile/consumer/EmptyActivity.kt b/benchmark/integration-tests/baselineprofile-consumer/src/main/java/androidx/benchmark/integration/baselineprofile/consumer/EmptyActivity.kt
index 6e88199..f614d57 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/src/main/java/androidx/benchmark/integration/baselineprofile/consumer/EmptyActivity.kt
+++ b/benchmark/integration-tests/baselineprofile-consumer/src/main/java/androidx/benchmark/integration/baselineprofile/consumer/EmptyActivity.kt
@@ -19,11 +19,27 @@
 import android.app.Activity
 import android.os.Bundle
 import android.widget.TextView
+import androidx.profileinstaller.ProfileVerifier
+import java.util.concurrent.Executors
 
 class EmptyActivity : Activity() {
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
-        findViewById<TextView>(R.id.txtNotice).setText(R.string.app_notice)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        Executors.newSingleThreadExecutor().submit {
+            val result = ProfileVerifier.getCompilationStatusAsync().get()
+            runOnUiThread {
+                findViewById<TextView>(R.id.txtNotice).text = """
+                    Profile installed: ${result.profileInstallResultCode}
+                    Has reference profile: ${result.isCompiledWithProfile}
+                    Has current profile: ${result.hasProfileEnqueuedForCompilation()}
+                """.trimIndent()
+            }
+        }
     }
 }
diff --git a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
index aa55e97..59b9c7d 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
+++ b/benchmark/integration-tests/baselineprofile-consumer/src/release/generated/baselineProfiles/expected-baseline-prof.txt
@@ -1,3 +1,272 @@
+Landroidx/appcompat/view/menu/MenuPresenter$Callback;
+Landroidx/appcompat/widget/TintTypedArray;
+HSPLandroidx/appcompat/widget/TintTypedArray;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/appcompat/widget/TintTypedArray;->measure(Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Z)Z
+HSPLandroidx/appcompat/widget/TintTypedArray;->solveLinearSystem(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;II)V
 Landroidx/benchmark/integration/baselineprofile/consumer/EmptyActivity;
 HSPLandroidx/benchmark/integration/baselineprofile/consumer/EmptyActivity;-><init>()V
-HSPLandroidx/benchmark/integration/baselineprofile/consumer/EmptyActivity;->onCreate(Landroid/os/Bundle;)V
\ No newline at end of file
+HSPLandroidx/benchmark/integration/baselineprofile/consumer/EmptyActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/benchmark/integration/baselineprofile/consumer/EmptyActivity;->onResume()V
+Landroidx/collection/ArrayMap$1;
+HSPLandroidx/collection/ArrayMap$1;-><init>()V
+Landroidx/concurrent/futures/AbstractResolvableFuture;
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture;-><clinit>()V
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture;-><init>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->complete(Landroidx/concurrent/futures/AbstractResolvableFuture;)V
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture;->get()Ljava/lang/Object;
+PLandroidx/concurrent/futures/AbstractResolvableFuture;->getDoneValue(Ljava/lang/Object;)Ljava/lang/Object;
+Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Listener;-><clinit>()V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$Listener;-><init>()V
+Landroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;-><init>(Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;)V
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casListeners(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Listener;)Z
+PLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casValue(Landroidx/concurrent/futures/AbstractResolvableFuture;Ljava/lang/Object;Ljava/lang/Object;)Z
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->casWaiters(Landroidx/concurrent/futures/AbstractResolvableFuture;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;)Z
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->putNext(Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;)V
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$SafeAtomicHelper;->putThread(Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;Ljava/lang/Thread;)V
+Landroidx/concurrent/futures/AbstractResolvableFuture$Waiter;
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><clinit>()V
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><init>()V
+HSPLandroidx/concurrent/futures/AbstractResolvableFuture$Waiter;-><init>(I)V
+Landroidx/concurrent/futures/ResolvableFuture;
+HSPLandroidx/concurrent/futures/ResolvableFuture;-><init>()V
+Landroidx/constraintlayout/solver/ArrayLinkedVariables;
+HSPLandroidx/constraintlayout/solver/ArrayLinkedVariables;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+Landroidx/constraintlayout/solver/ArrayRow;
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->addError(Landroidx/constraintlayout/solver/LinearSystem;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->pivot(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->reset()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromFinalVariable(Landroidx/constraintlayout/solver/SolverVariable;Z)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+Landroidx/constraintlayout/solver/ArrayRow$ArrayRowVariables;
+Landroidx/constraintlayout/solver/LinearSystem;
+HSPLandroidx/constraintlayout/solver/LinearSystem;-><init>()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->acquireSolverVariable$enumunboxing$(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addCentering(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IFLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addConstraint(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createErrorVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createObjectVariable(Ljava/lang/Object;)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createRow()Landroidx/constraintlayout/solver/ArrayRow;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createSlackVariable()Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->getObjectVariableValue(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;)I
+HSPLandroidx/constraintlayout/solver/LinearSystem;->increaseTableSize()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->optimize(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->releaseRows()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->reset()V
+Landroidx/constraintlayout/solver/LinearSystem$ValuesRow;
+HSPLandroidx/constraintlayout/solver/LinearSystem$ValuesRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+Landroidx/constraintlayout/solver/Pools$SimplePool;
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;-><init>()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->acquire()Ljava/lang/Object;
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->release(Landroidx/constraintlayout/solver/ArrayRow;)V
+Landroidx/constraintlayout/solver/PriorityGoalRow;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->addToGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->getPivotCandidate([Z)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->removeGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+Landroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;-><init>(Landroidx/constraintlayout/solver/PriorityGoalRow;)V
+Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/SolverVariable;-><init>(I)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->addToRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->removeFromRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->reset()V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->updateReferencesWithNewDefinition(Landroidx/constraintlayout/solver/ArrayRow;)V
+Landroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;->ordinal(I)I
+Landroidx/constraintlayout/solver/SolverVariableValues;
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->add(Landroidx/constraintlayout/solver/SolverVariable;FZ)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addToHashMap(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addVariable(ILandroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->clear()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->divideByAmount(F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->get(Landroidx/constraintlayout/solver/SolverVariable;)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getCurrentSize()I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariableValue(I)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->indexOf(Landroidx/constraintlayout/solver/SolverVariable;)I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->invert()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->put(Landroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->remove(Landroidx/constraintlayout/solver/SolverVariable;Z)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->use(Landroidx/constraintlayout/solver/ArrayRow;Z)F
+Landroidx/constraintlayout/solver/widgets/Barrier;
+Landroidx/constraintlayout/solver/widgets/ChainHead;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->connect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->getMargin()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->isConnected()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->resetSolverVariable()V
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><init>(ILjava/lang/String;)V
+Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->addToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->applyConstraints$enumunboxing$(Landroidx/constraintlayout/solver/LinearSystem;ZZZZLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IZLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;IIIIFZZZZIIIIFZ)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->createObjectVariables(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getAnchor(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getDimensionBehaviour$enumunboxing$(I)I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getHeight()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getWidth()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getX()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getY()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->immediateConnect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isChainHead(I)Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInHorizontalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInVerticalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHeight(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHorizontalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setVerticalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setWidth(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->updateFromSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->addChildrenToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->layout()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+Landroidx/constraintlayout/solver/widgets/Guideline;
+Landroidx/constraintlayout/solver/widgets/Helper;
+Landroidx/constraintlayout/solver/widgets/HelperWidget;
+Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;-><init>()V
+Landroidx/constraintlayout/solver/widgets/analyzer/Dependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+Landroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+Landroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+Landroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+Landroidx/constraintlayout/widget/ConstraintHelper;
+Landroidx/constraintlayout/widget/ConstraintLayout;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->applyConstraintsFromLayoutParams(ZLandroid/view/View;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;Landroid/util/SparseArray;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->checkLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getPaddingWidth()I
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getViewWidget(Landroid/view/View;)Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->isRtl()Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onLayout(ZIIII)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onMeasure(II)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onViewAdded(Landroid/view/View;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->requestLayout()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->updateHierarchy()Z
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->resolveLayoutDirection(I)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->validate()V
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;-><clinit>()V
+Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;-><init>(Landroidx/constraintlayout/widget/ConstraintLayout;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
+Landroidx/constraintlayout/widget/Guideline;
+Landroidx/constraintlayout/widget/R$styleable;
+HSPLandroidx/constraintlayout/widget/R$styleable;-><clinit>()V
+Landroidx/core/app/CoreComponentFactory;
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateProvider(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/content/ContentProvider;
+PLandroidx/core/app/CoreComponentFactory;->instantiateReceiver(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/content/BroadcastReceiver;
+Landroidx/core/view/ViewCompat$$ExternalSyntheticApiModelOutline2;
+HSPLandroidx/core/view/ViewCompat$$ExternalSyntheticApiModelOutline2;->m()Landroid/view/Choreographer;
+HSPLandroidx/core/view/ViewCompat$$ExternalSyntheticApiModelOutline2;->m(Landroid/view/Choreographer;Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda2;)V
+Landroidx/core/view/ViewCompat$3$$ExternalSyntheticApiModelOutline0;
+HSPLandroidx/core/view/ViewCompat$3$$ExternalSyntheticApiModelOutline0;->m(Landroid/os/Looper;)Landroid/os/Handler;
+PLandroidx/profileinstaller/ProfileInstallReceiver;-><init>()V
+PLandroidx/profileinstaller/ProfileInstallReceiver;->onReceive(Landroid/content/Context;Landroid/content/Intent;)V
+PLandroidx/profileinstaller/ProfileInstaller$$ExternalSyntheticLambda1;-><init>(I)V
+Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;
+Landroidx/profileinstaller/ProfileInstallerInitializer;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer;-><init>()V
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;-><init>(ILjava/lang/Object;Ljava/lang/Object;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda0;->run()V
+Landroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;-><init>(Landroid/content/Context;I)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$$ExternalSyntheticLambda1;->run()V
+Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl;->postFrameCallback(Ljava/lang/Runnable;)V
+Landroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda2;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda2;-><init>(Ljava/lang/Runnable;)V
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Choreographer16Impl$$ExternalSyntheticLambda2;->doFrame(J)V
+Landroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;
+HSPLandroidx/profileinstaller/ProfileInstallerInitializer$Handler28Impl;->createAsync(Landroid/os/Looper;)Landroid/os/Handler;
+Landroidx/profileinstaller/ProfileVerifier;
+HSPLandroidx/profileinstaller/ProfileVerifier;-><clinit>()V
+PLandroidx/profileinstaller/ProfileVerifier;->setCompilationStatus(IZZ)Landroidx/profileinstaller/ProfileVerifier$CompilationStatus;
+PLandroidx/profileinstaller/ProfileVerifier;->writeProfileVerification(Landroid/content/Context;Z)V
+PLandroidx/profileinstaller/ProfileVerifier$Api33Impl;->getPackageInfo(Landroid/content/pm/PackageManager;Landroid/content/Context;)Landroid/content/pm/PackageInfo;
+PLandroidx/profileinstaller/ProfileVerifier$Api33Impl$$ExternalSyntheticApiModelOutline0;->m()Landroid/content/pm/PackageManager$PackageInfoFlags;
+PLandroidx/profileinstaller/ProfileVerifier$Api33Impl$$ExternalSyntheticApiModelOutline0;->m(Landroid/content/pm/PackageManager;Ljava/lang/String;Landroid/content/pm/PackageManager$PackageInfoFlags;)Landroid/content/pm/PackageInfo;
+PLandroidx/profileinstaller/ProfileVerifier$Cache;-><init>(IIJJ)V
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->equals(Ljava/lang/Object;)Z
+PLandroidx/profileinstaller/ProfileVerifier$Cache;->readFromFile(Ljava/io/File;)Landroidx/profileinstaller/ProfileVerifier$Cache;
+PLandroidx/profileinstaller/ProfileVerifier$CompilationStatus;-><init>(IZZ)V
+Landroidx/startup/AppInitializer;
+HSPLandroidx/startup/AppInitializer;-><clinit>()V
+HSPLandroidx/startup/AppInitializer;-><init>(Landroid/content/Context;)V
+HSPLandroidx/startup/AppInitializer;->discoverAndInitialize(Landroid/os/Bundle;)V
+HSPLandroidx/startup/AppInitializer;->doInitialize(Ljava/lang/Class;Ljava/util/HashSet;)V
+Landroidx/startup/InitializationProvider;
+HSPLandroidx/startup/InitializationProvider;-><init>()V
+HSPLandroidx/startup/InitializationProvider;->onCreate()Z
+Landroidx/tracing/Trace;
+HSPLandroidx/tracing/Trace;->isEnabled()Z
+Landroidx/tracing/Trace$$ExternalSyntheticApiModelOutline0;
+HSPLandroidx/tracing/Trace$$ExternalSyntheticApiModelOutline0;->m()Z
+Landroidx/tracing/TraceApi18Impl$$ExternalSyntheticApiModelOutline0;
+HSPLandroidx/tracing/TraceApi18Impl$$ExternalSyntheticApiModelOutline0;->m()V
+HSPLandroidx/tracing/TraceApi18Impl$$ExternalSyntheticApiModelOutline0;->m(Ljava/lang/String;)V
+PLkotlin/Pair;-><init>(Ljava/lang/Object;Ljava/lang/Object;)V
+Lkotlin/TuplesKt;
+HSPLkotlin/TuplesKt;-><clinit>()V
+HSPLkotlin/TuplesKt;-><init>(Ljava/lang/Object;)V
+PLkotlin/TuplesKt;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
+HSPLkotlin/TuplesKt;->checkNotNullParameter(Ljava/lang/Object;Ljava/lang/String;)V
+PLkotlin/TuplesKt;->writeProfile(Landroid/content/Context;Landroidx/profileinstaller/ProfileInstaller$$ExternalSyntheticLambda1;Landroidx/profileinstaller/ProfileInstaller$DiagnosticsCallback;Z)V
+PLkotlin/jvm/internal/Lambda;-><init>()V
+PLkotlin/ranges/IntProgression;-><init>(III)V
+PLkotlin/ranges/IntProgression;->iterator()Ljava/util/Iterator;
+PLkotlin/ranges/IntProgressionIterator;-><init>(III)V
+PLkotlin/ranges/IntRange;-><clinit>()V
+PLkotlin/ranges/IntRange;-><init>(II)V
+Lkotlin/ranges/IntRange$Companion;
+HSPLkotlin/ranges/IntRange$Companion;-><init>(I)V
+PLkotlin/ranges/IntRange$Companion;->onResultReceived(ILjava/lang/Object;)V
+PLkotlin/text/DelimitedRangesSequence;-><init>(Ljava/lang/String;IILkotlin/text/StringsKt__StringsKt$rangesDelimitedBy$2;)V
+PLkotlin/text/DelimitedRangesSequence;->iterator()Ljava/util/Iterator;
+PLkotlin/text/DelimitedRangesSequence$iterator$1;-><init>(Lkotlin/text/DelimitedRangesSequence;)V
+PLkotlin/text/DelimitedRangesSequence$iterator$1;->calcNext()V
+PLkotlin/text/DelimitedRangesSequence$iterator$1;->hasNext()Z
+PLkotlin/text/DelimitedRangesSequence$iterator$1;->next()Ljava/lang/Object;
+PLkotlin/text/StringsKt__StringsKt;->isBlank(Ljava/lang/String;)Z
+PLkotlin/text/StringsKt__StringsKt$rangesDelimitedBy$2;-><init>(Ljava/util/List;Z)V
+PLkotlin/text/StringsKt__StringsKt$splitToSequence$1;-><init>(ILjava/lang/String;)V
+PLkotlin/text/StringsKt__StringsKt$splitToSequence$1;->invoke(Ljava/lang/Object;)Ljava/lang/String;
\ No newline at end of file
diff --git a/benchmark/integration-tests/baselineprofile-test-utils/utils.gradle b/benchmark/integration-tests/baselineprofile-test-utils/utils.gradle
index e1d139e..b8a42a7 100644
--- a/benchmark/integration-tests/baselineprofile-test-utils/utils.gradle
+++ b/benchmark/integration-tests/baselineprofile-test-utils/utils.gradle
@@ -1,3 +1,4 @@
+import com.android.build.api.artifact.SingleArtifact
 import org.gradle.work.DisableCachingByDefault
 
 import static androidx.baselineprofile.gradle.utils.UtilsKt.camelCase
diff --git a/bluetooth/bluetooth/build.gradle b/bluetooth/bluetooth/build.gradle
index 445c7ab..5bcf6c2 100644
--- a/bluetooth/bluetooth/build.gradle
+++ b/bluetooth/bluetooth/build.gradle
@@ -47,6 +47,6 @@
 android {
     namespace "androidx.bluetooth"
     defaultConfig {
-        minSdkVersion 21
+        minSdkVersion 31
     }
 }
diff --git a/bluetooth/integration-tests/testapp/build.gradle b/bluetooth/integration-tests/testapp/build.gradle
index 07c8703..860d815 100644
--- a/bluetooth/integration-tests/testapp/build.gradle
+++ b/bluetooth/integration-tests/testapp/build.gradle
@@ -24,8 +24,8 @@
 
 android {
     defaultConfig {
-        minSdkVersion 28
-        targetSdkVersion 31
+        minSdkVersion 31
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
     }
@@ -48,17 +48,17 @@
     implementation(project(":bluetooth:bluetooth"))
 
     implementation("androidx.core:core-ktx:1.9.0")
-    implementation("androidx.appcompat:appcompat:1.6.0")
+    implementation("androidx.appcompat:appcompat:1.6.1")
 
     implementation(libs.material)
 
-    implementation("androidx.activity:activity-ktx:1.6.1")
-    implementation("androidx.fragment:fragment-ktx:1.5.5")
+    implementation("androidx.activity:activity-ktx:1.7.0")
+    implementation("androidx.fragment:fragment-ktx:1.5.6")
 
     implementation(libs.constraintLayout)
 
-    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1")
-    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
+    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
+    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
 
     implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
     implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
index 634a638..aa29ddb 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
@@ -25,6 +25,8 @@
 import androidx.navigation.findNavController
 import androidx.navigation.ui.AppBarConfiguration
 import androidx.navigation.ui.setupActionBarWithNavController
+import androidx.navigation.ui.setupWithNavController
+import com.google.android.material.bottomnavigation.BottomNavigationView
 
 class MainActivity : AppCompatActivity() {
 
@@ -47,11 +49,14 @@
         binding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
+        val navView: BottomNavigationView = binding.navView
+
         val navController = findNavController(R.id.nav_host_fragment_activity_main)
         val appBarConfiguration = AppBarConfiguration(
-            setOf(R.id.navigation_home)
+            setOf(R.id.navigation_home, R.id.navigation_scanner, R.id.navigation_advertiser)
         )
         setupActionBarWithNavController(navController, appBarConfiguration)
+        navView.setupWithNavController(navController)
     }
 
     override fun onResume() {
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
index 6b0459e..81aba53 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
@@ -39,6 +39,7 @@
 internal class GattClientImpl {
     companion object {
         private const val TAG = "GattClientImpl"
+        private const val GATT_MAX_MTU = 517
     }
     private data class ClientTask(
         val taskBlock: () -> Unit
@@ -75,11 +76,21 @@
         val callback = object : BluetoothGattCallback() {
             override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
                 if (newState == BluetoothGatt.STATE_CONNECTED) {
+                    gatt?.requestMtu(GATT_MAX_MTU)
+                } else {
+                    connectResult.complete(false)
+                    // TODO(b/270492198): throw precise exception
+                    finished.completeExceptionally(IllegalStateException("connect failed"))
+                }
+            }
+
+            override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
+                if (status == GATT_SUCCESS) {
                     gatt?.discoverServices()
                 } else {
                     connectResult.complete(false)
-                    // TODO: throw precise exception
-                    finished.completeExceptionally(IllegalStateException("??"))
+                    // TODO(b/270492198): throw precise exception
+                    finished.completeExceptionally(IllegalStateException("mtu request failed"))
                 }
             }
 
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
new file mode 100644
index 0000000..3f12108
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/advertiser/AdvertiserFragment.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.integration.testapp.ui.advertiser
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.bluetooth.integration.testapp.databinding.FragmentAdvertiserBinding
+import androidx.fragment.app.Fragment
+
+class AdvertiserFragment : Fragment() {
+
+    companion object {
+        private const val TAG = "AdvertiserFragment"
+    }
+
+    private var _binding: FragmentAdvertiserBinding? = null
+
+    // This property is only valid between onCreateView and onDestroyView.
+    private val binding get() = _binding!!
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        Log.d(
+            TAG, "onCreateView() called with: inflater = $inflater, " +
+                "container = $container, savedInstanceState = $savedInstanceState"
+        )
+
+        _binding = FragmentAdvertiserBinding.inflate(inflater, container, false)
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
index 3e3cb75..70943a0 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/home/HomeFragment.kt
@@ -29,7 +29,6 @@
 import android.view.ViewGroup
 import android.widget.Toast
 import androidx.bluetooth.integration.testapp.R
-import androidx.bluetooth.integration.testapp.data.SampleAdvertiseData
 import androidx.bluetooth.integration.testapp.databinding.FragmentHomeBinding
 import androidx.bluetooth.integration.testapp.experimental.AdvertiseResult
 import androidx.bluetooth.integration.testapp.experimental.BluetoothLe
@@ -185,7 +184,6 @@
             .build()
 
         val advertiseData = AdvertiseData.Builder()
-            .addServiceUuid(SampleAdvertiseData.testUUID)
             .setIncludeDeviceName(true)
             .build()
 
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
new file mode 100644
index 0000000..ec8e6d9
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/scanner/ScannerFragment.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.integration.testapp.ui.scanner
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.bluetooth.integration.testapp.databinding.FragmentScannerBinding
+import androidx.fragment.app.Fragment
+
+class ScannerFragment : Fragment() {
+
+    companion object {
+        private const val TAG = "ScannerFragment"
+    }
+
+    private var _binding: FragmentScannerBinding? = null
+
+    // This property is only valid between onCreateView and onDestroyView.
+    private val binding get() = _binding!!
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        Log.d(
+            TAG, "onCreateView() called with: inflater = $inflater, " +
+                "container = $container, savedInstanceState = $savedInstanceState"
+        )
+
+        _binding = FragmentScannerBinding.inflate(inflater, container, false)
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
diff --git a/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_bluetooth_searching_24.xml b/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_bluetooth_searching_24.xml
new file mode 100644
index 0000000..0e722c2
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_bluetooth_searching_24.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector android:autoMirrored="true" android:height="24dp"
+    android:tint="#000000" android:viewportHeight="24"
+    android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M14.24,12.01l2.32,2.32c0.28,-0.72 0.44,-1.51 0.44,-2.33 0,-0.82 -0.16,-1.59 -0.43,-2.31l-2.33,2.32zM19.53,6.71l-1.26,1.26c0.63,1.21 0.98,2.57 0.98,4.02s-0.36,2.82 -0.98,4.02l1.2,1.2c0.97,-1.54 1.54,-3.36 1.54,-5.31 -0.01,-1.89 -0.55,-3.67 -1.48,-5.19zM15.71,7.71L10,2L9,2v7.59L4.41,5 3,6.41 8.59,12 3,17.59 4.41,19 9,14.41L9,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM11,5.83l1.88,1.88L11,9.59L11,5.83zM12.88,16.29L11,18.17v-3.76l1.88,1.88z"/>
+</vector>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_wb_iridescent_24.xml b/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_wb_iridescent_24.xml
new file mode 100644
index 0000000..37762ce
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/drawable/baseline_wb_iridescent_24.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M5,14.5h14v-6L5,8.5v6zM11,0.55L11,3.5h2L13,0.55h-2zM19.04,3.05l-1.79,1.79 1.41,1.41 1.8,-1.79 -1.42,-1.41zM13,22.45L13,19.5h-2v2.95h2zM20.45,18.54l-1.8,-1.79 -1.41,1.41 1.79,1.8 1.42,-1.42zM3.55,4.46l1.79,1.79 1.41,-1.41 -1.79,-1.79 -1.41,1.41zM4.96,19.95l1.79,-1.8 -1.41,-1.41 -1.79,1.79 1.41,1.42z"/>
+</vector>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
index ad75688..4c9b86fb 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/activity_main.xml
@@ -23,6 +23,18 @@
     android:layout_height="match_parent"
     tools:context=".MainActivity">
 
+    <com.google.android.material.bottomnavigation.BottomNavigationView
+        android:id="@+id/nav_view"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="0dp"
+        android:layout_marginEnd="0dp"
+        android:background="?android:attr/windowBackground"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:menu="@menu/bottom_nav_menu" />
+
     <fragment
         android:id="@+id/nav_host_fragment_activity_main"
         android:name="androidx.navigation.fragment.NavHostFragment"
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_advertiser.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_advertiser.xml
new file mode 100644
index 0000000..14e7b3e
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_advertiser.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml
new file mode 100644
index 0000000..14e7b3e
--- /dev/null
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_scanner.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/menu/bottom_nav_menu.xml b/bluetooth/integration-tests/testapp/src/main/res/menu/bottom_nav_menu.xml
index 87e60bd..68f6353 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/menu/bottom_nav_menu.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/menu/bottom_nav_menu.xml
@@ -21,4 +21,14 @@
         android:icon="@drawable/ic_bluetooth_24"
         android:title="@string/title_home" />
 
+    <item
+        android:id="@+id/navigation_scanner"
+        android:icon="@drawable/baseline_bluetooth_searching_24"
+        android:title="@string/title_scanner" />
+
+    <item
+        android:id="@+id/navigation_advertiser"
+        android:icon="@drawable/baseline_wb_iridescent_24"
+        android:title="@string/title_advertiser" />
+
 </menu>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/navigation/nav_graph.xml b/bluetooth/integration-tests/testapp/src/main/res/navigation/nav_graph.xml
index 2713795..b3c74a1 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/navigation/nav_graph.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/navigation/nav_graph.xml
@@ -26,4 +26,16 @@
         android:label="@string/title_home"
         tools:layout="@layout/fragment_home" />
 
+    <fragment
+        android:id="@+id/navigation_scanner"
+        android:name="androidx.bluetooth.integration.testapp.ui.scanner.ScannerFragment"
+        android:label="@string/title_scanner"
+        tools:layout="@layout/fragment_home" />
+
+    <fragment
+        android:id="@+id/navigation_advertiser"
+        android:name="androidx.bluetooth.integration.testapp.ui.advertiser.AdvertiserFragment"
+        android:label="@string/title_advertiser"
+        tools:layout="@layout/fragment_home" />
+
 </navigation>
diff --git a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
index 4ec5c99..d60cf5c 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
@@ -18,6 +18,8 @@
     <string name="app_name">AndroidX Bluetooth Test App</string>
 
     <string name="title_home">AndroidX Bluetooth</string>
+    <string name="title_scanner">Scanner</string>
+    <string name="title_advertiser">Advertiser</string>
 
     <string name="scan_using_androidx_bluetooth">Scan using AndroidX Bluetooth APIs</string>
     <string name="scan_start_message">Scan started. Results are in Logcat</string>
diff --git a/browser/browser/api/current.txt b/browser/browser/api/current.txt
index 1cb34f0..42d5a3b 100644
--- a/browser/browser/api/current.txt
+++ b/browser/browser/api/current.txt
@@ -203,7 +203,7 @@
     method @androidx.browser.customtabs.CustomTabsService.Result protected abstract int postMessage(androidx.browser.customtabs.CustomTabsSessionToken, String, android.os.Bundle?);
     method protected abstract boolean receiveFile(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, int, android.os.Bundle?);
     method protected abstract boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri);
-    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallbackRemote, android.os.Bundle);
+    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle);
     method protected abstract boolean updateVisuals(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle?);
     method protected abstract boolean validateRelationship(androidx.browser.customtabs.CustomTabsSessionToken, @androidx.browser.customtabs.CustomTabsService.Relation int, android.net.Uri, android.os.Bundle?);
     method protected abstract boolean warmup(long);
@@ -265,12 +265,6 @@
     method public default void onVerticalScrollEvent(boolean, android.os.Bundle);
   }
 
-  public final class EngagementSignalsCallbackRemote {
-    method public void onGreatestScrollPercentageIncreased(@IntRange(from=1, to=100) int, android.os.Bundle) throws android.os.RemoteException;
-    method public void onSessionEnded(boolean, android.os.Bundle) throws android.os.RemoteException;
-    method public void onVerticalScrollEvent(boolean, android.os.Bundle) throws android.os.RemoteException;
-  }
-
   public class PostMessageService extends android.app.Service {
     ctor public PostMessageService();
     method public android.os.IBinder onBind(android.content.Intent?);
diff --git a/browser/browser/api/public_plus_experimental_current.txt b/browser/browser/api/public_plus_experimental_current.txt
index 1cb34f0..42d5a3b 100644
--- a/browser/browser/api/public_plus_experimental_current.txt
+++ b/browser/browser/api/public_plus_experimental_current.txt
@@ -203,7 +203,7 @@
     method @androidx.browser.customtabs.CustomTabsService.Result protected abstract int postMessage(androidx.browser.customtabs.CustomTabsSessionToken, String, android.os.Bundle?);
     method protected abstract boolean receiveFile(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, int, android.os.Bundle?);
     method protected abstract boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri);
-    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallbackRemote, android.os.Bundle);
+    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle);
     method protected abstract boolean updateVisuals(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle?);
     method protected abstract boolean validateRelationship(androidx.browser.customtabs.CustomTabsSessionToken, @androidx.browser.customtabs.CustomTabsService.Relation int, android.net.Uri, android.os.Bundle?);
     method protected abstract boolean warmup(long);
@@ -265,12 +265,6 @@
     method public default void onVerticalScrollEvent(boolean, android.os.Bundle);
   }
 
-  public final class EngagementSignalsCallbackRemote {
-    method public void onGreatestScrollPercentageIncreased(@IntRange(from=1, to=100) int, android.os.Bundle) throws android.os.RemoteException;
-    method public void onSessionEnded(boolean, android.os.Bundle) throws android.os.RemoteException;
-    method public void onVerticalScrollEvent(boolean, android.os.Bundle) throws android.os.RemoteException;
-  }
-
   public class PostMessageService extends android.app.Service {
     ctor public PostMessageService();
     method public android.os.IBinder onBind(android.content.Intent?);
diff --git a/browser/browser/api/restricted_current.txt b/browser/browser/api/restricted_current.txt
index 20835a4..19a1da2 100644
--- a/browser/browser/api/restricted_current.txt
+++ b/browser/browser/api/restricted_current.txt
@@ -214,7 +214,7 @@
     method @androidx.browser.customtabs.CustomTabsService.Result protected abstract int postMessage(androidx.browser.customtabs.CustomTabsSessionToken, String, android.os.Bundle?);
     method protected abstract boolean receiveFile(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri, int, android.os.Bundle?);
     method protected abstract boolean requestPostMessageChannel(androidx.browser.customtabs.CustomTabsSessionToken, android.net.Uri);
-    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallbackRemote, android.os.Bundle);
+    method protected boolean setEngagementSignalsCallback(androidx.browser.customtabs.CustomTabsSessionToken, androidx.browser.customtabs.EngagementSignalsCallback, android.os.Bundle);
     method protected abstract boolean updateVisuals(androidx.browser.customtabs.CustomTabsSessionToken, android.os.Bundle?);
     method protected abstract boolean validateRelationship(androidx.browser.customtabs.CustomTabsSessionToken, @androidx.browser.customtabs.CustomTabsService.Relation int, android.net.Uri, android.os.Bundle?);
     method protected abstract boolean warmup(long);
@@ -276,12 +276,6 @@
     method public default void onVerticalScrollEvent(boolean, android.os.Bundle);
   }
 
-  public final class EngagementSignalsCallbackRemote {
-    method public void onGreatestScrollPercentageIncreased(@IntRange(from=1, to=100) int, android.os.Bundle) throws android.os.RemoteException;
-    method public void onSessionEnded(boolean, android.os.Bundle) throws android.os.RemoteException;
-    method public void onVerticalScrollEvent(boolean, android.os.Bundle) throws android.os.RemoteException;
-  }
-
   public class PostMessageService extends android.app.Service {
     ctor public PostMessageService();
     method public android.os.IBinder onBind(android.content.Intent?);
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
index 8747f31..ee1e791 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/CustomTabsService.java
@@ -274,7 +274,7 @@
         public boolean setEngagementSignalsCallback(
                 @NonNull ICustomTabsCallback customTabsCallback, @NonNull IBinder callback,
                 @NonNull Bundle extras) {
-            EngagementSignalsCallbackRemote remote = EngagementSignalsCallbackRemote.fromBinder(
+            EngagementSignalsCallback remote = EngagementSignalsCallbackRemote.fromBinder(
                     callback);
             return CustomTabsService.this.setEngagementSignalsCallback(
                     new CustomTabsSessionToken(customTabsCallback, getSessionIdFromBundle(extras)),
@@ -506,11 +506,11 @@
     }
 
     /**
-     * Sets an {@link EngagementSignalsCallbackRemote} to execute callbacks for events related to
+     * Sets an {@link EngagementSignalsCallback} to execute callbacks for events related to
      * the user's engagement with the webpage within the tab.
      *
      * @param sessionToken The unique identifier for the session.
-     * @param callback The {@link EngagementSignalsCallbackRemote} to execute the callbacks.
+     * @param callback The {@link EngagementSignalsCallback} to execute the callbacks.
      * @param extras Reserved for future use.
      * @return Whether the callback connection is allowed. If false, no callbacks will be called for
      *         this session.
@@ -520,7 +520,7 @@
     @SuppressWarnings("ExecutorRegistration")
     protected boolean setEngagementSignalsCallback(
             @NonNull CustomTabsSessionToken sessionToken,
-            @NonNull EngagementSignalsCallbackRemote callback, @NonNull Bundle extras) {
+            @NonNull EngagementSignalsCallback callback, @NonNull Bundle extras) {
         return false;
     }
 
diff --git a/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallbackRemote.java b/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallbackRemote.java
index 9e02c71..44dcc86 100644
--- a/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallbackRemote.java
+++ b/browser/browser/src/main/java/androidx/browser/customtabs/EngagementSignalsCallbackRemote.java
@@ -20,16 +20,21 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.support.customtabs.IEngagementSignalsCallback;
+import android.util.Log;
 
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
 
 /**
  * Remote class used to execute callbacks from a binder of {@link EngagementSignalsCallback}. This
  * is a thin wrapper around {@link IEngagementSignalsCallback} that is passed to the Custom Tabs
  * implementation for the calls across process boundaries.
  */
-public final class EngagementSignalsCallbackRemote {
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+/* package */ final class EngagementSignalsCallbackRemote implements EngagementSignalsCallback {
+    private static final String TAG = "EngagementSigsCallbkRmt";
+
     private final IEngagementSignalsCallback mCallbackBinder;
 
     private EngagementSignalsCallbackRemote(@NonNull IEngagementSignalsCallback callbackBinder) {
@@ -53,9 +58,13 @@
      *                      user scrolls back up toward the top of the page.
      * @param extras Reserved for future use.
      */
-    public void onVerticalScrollEvent(boolean isDirectionUp, @NonNull Bundle extras) throws
-            RemoteException {
-        mCallbackBinder.onVerticalScrollEvent(isDirectionUp, extras);
+    @Override
+    public void onVerticalScrollEvent(boolean isDirectionUp, @NonNull Bundle extras) {
+        try {
+            mCallbackBinder.onVerticalScrollEvent(isDirectionUp, extras);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException during IEngagementSignalsCallback transaction");
+        }
     }
 
     /**
@@ -68,10 +77,14 @@
      *                         made down the current page.
      * @param extras Reserved for future use.
      */
+    @Override
     public void onGreatestScrollPercentageIncreased(
-            @IntRange(from = 1, to = 100) int scrollPercentage, @NonNull Bundle extras) throws
-            RemoteException {
-        mCallbackBinder.onGreatestScrollPercentageIncreased(scrollPercentage, extras);
+            @IntRange(from = 1, to = 100) int scrollPercentage, @NonNull Bundle extras) {
+        try {
+            mCallbackBinder.onGreatestScrollPercentageIncreased(scrollPercentage, extras);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException during IEngagementSignalsCallback transaction");
+        }
     }
 
     /**
@@ -82,8 +95,12 @@
      *                        scrolling.
      * @param extras Reserved for future use.
      */
-    public void onSessionEnded(boolean didUserInteract, @NonNull Bundle extras)
-            throws RemoteException {
-        mCallbackBinder.onSessionEnded(didUserInteract, extras);
+    @Override
+    public void onSessionEnded(boolean didUserInteract, @NonNull Bundle extras) {
+        try {
+            mCallbackBinder.onSessionEnded(didUserInteract, extras);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException during IEngagementSignalsCallback transaction");
+        }
     }
 }
diff --git a/buildSrc-tests/src/test/kotlin/androidx/build/KmpPlatformsTest.kt b/buildSrc-tests/src/test/kotlin/androidx/build/KmpPlatformsTest.kt
index c81ae66..c7e2ad8 100644
--- a/buildSrc-tests/src/test/kotlin/androidx/build/KmpPlatformsTest.kt
+++ b/buildSrc-tests/src/test/kotlin/androidx/build/KmpPlatformsTest.kt
@@ -23,69 +23,63 @@
 
     @Test
     fun withAnEmptyFlag_itReturnsTheDefaultValue() {
-        assertThat(KmpFlagParser.parse("")).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.DESKTOP)
-        )
+        assertThat(KmpFlagParser.parse("")).isEqualTo(setOf(KmpPlatform.JVM))
     }
 
     @Test
     fun withANullFlag_itReturnsTheDefaultValue() {
-        assertThat(KmpFlagParser.parse(null)).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.DESKTOP)
-        )
+        assertThat(KmpFlagParser.parse(null)).isEqualTo(setOf(KmpPlatform.JVM))
     }
 
     @Test
     fun withASingleDefaultPlatform_itParsesTheFlagCorrectly() {
-        assertThat(KmpFlagParser.parse("+jvm")).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.DESKTOP)
-        )
+        assertThat(KmpFlagParser.parse("+jvm")).isEqualTo(setOf(KmpPlatform.JVM))
     }
 
     @Test
     fun withNoPlatforms_itParsesTheFlagCorrectly() {
-        assertThat(KmpFlagParser.parse("-jvm,-desktop")).isEqualTo(emptySet<KmpPlatform>())
+        assertThat(KmpFlagParser.parse("-jvm")).isEqualTo(emptySet<KmpPlatform>())
     }
 
     @Test
     fun withASingleNonDefaultPlatform_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("+js")).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.JS, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.JVM, KmpPlatform.JS)
         )
     }
 
     @Test
     fun withAMultiplePlatforms_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("+js,+mac")).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.JS, KmpPlatform.MAC, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.JVM, KmpPlatform.JS, KmpPlatform.MAC)
         )
     }
 
     @Test
     fun withNegativeFlags_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("-jvm,+mac")).isEqualTo(
-            setOf(KmpPlatform.MAC, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.MAC)
         )
     }
 
     @Test
     fun withTheNativeFlag_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("+native")).isEqualTo(
-            setOf(KmpPlatform.JVM, KmpPlatform.MAC, KmpPlatform.LINUX, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.JVM, KmpPlatform.MAC, KmpPlatform.LINUX)
         )
     }
 
     @Test
     fun withMultipleFlagsIncludingTheNativeFlag_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("-jvm,+native,+js")).isEqualTo(
-            setOf(KmpPlatform.JS, KmpPlatform.MAC, KmpPlatform.LINUX, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.JS, KmpPlatform.MAC, KmpPlatform.LINUX)
         )
     }
 
     @Test
     fun withRedundentFlags_itParsesTheFlagCorrectly() {
         assertThat(KmpFlagParser.parse("-jvm,+native,+linux,+mac,+linux")).isEqualTo(
-            setOf(KmpPlatform.MAC, KmpPlatform.LINUX, KmpPlatform.DESKTOP)
+            setOf(KmpPlatform.MAC, KmpPlatform.LINUX)
         )
     }
 }
\ No newline at end of file
diff --git a/buildSrc-tests/src/test/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTaskTest.kt b/buildSrc-tests/src/test/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTaskTest.kt
index 8166dff..a6a165e 100644
--- a/buildSrc-tests/src/test/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTaskTest.kt
+++ b/buildSrc-tests/src/test/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTaskTest.kt
@@ -29,6 +29,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TemporaryFolder
+import com.google.common.truth.Truth.assertThat
 
 class CreateLibraryBuildInfoFileTaskTest {
     @get:Rule
@@ -70,23 +71,23 @@
         val buildInfoFile = distDir.root.resolve(
             "build-info/androidx.build_info_test_test_build_info.txt"
         )
-        buildInfoFile.check { it.exists() }
+        assertThat(buildInfoFile.exists()).isTrue()
+
         val buildInfo = parseBuildInfo(buildInfoFile)
-        buildInfo.check {
-            it.groupId == "androidx.build_info_test"
-            it.artifactId == "test"
-            it.groupIdRequiresSameVersion == false
-            it.version == "0.0.1"
-            it.dependencies == listOf(
-                LibraryBuildInfoFile.Dependency().apply {
-                    groupId = "androidx.core"
-                    artifactId = "core"
-                    version = "1.1.0"
-                    isTipOfTree = false
-                }
-            )
-            it.kotlinVersion == projectSetup.props.kotlinVersion
-        }
+
+        assertThat(buildInfo.groupId).isEqualTo("androidx.build_info_test")
+        assertThat(buildInfo.artifactId).isEqualTo("test")
+        assertThat(buildInfo.version).isEqualTo("0.0.1")
+        assertThat(buildInfo.kotlinVersion).isEqualTo(projectSetup.props.kotlinVersion)
+        assertThat(buildInfo.groupIdRequiresSameVersion).isFalse()
+        assertThat(buildInfo.dependencies).hasSize(1)
+        assertThat(buildInfo.dependencies.single().groupId).isEqualTo("androidx.core")
+        assertThat(buildInfo.dependencies.single().artifactId).isEqualTo("core")
+        assertThat(buildInfo.dependencyConstraints).hasSize(1)
+        assertThat(buildInfo.dependencyConstraints.single().groupId)
+            .isEqualTo("androidx.core")
+        assertThat(buildInfo.dependencyConstraints.single().artifactId)
+            .isEqualTo("core-ktx")
     }
 
     fun setupBuildInfoProject() {
@@ -103,29 +104,36 @@
                 }
             """.trimIndent(),
             suffix = """
+            version = "0.0.1"
             dependencies {
+                constraints {
+                    implementation("androidx.core:core-ktx:1.1.0")
+                }
                 implementation("androidx.core:core:1.1.0")
             }
             android {
                  namespace 'androidx.build_info'
             }
             group = "androidx.build_info_test"
-            publishing {
-                publications {
-                    maven(MavenPublication) {
-                        groupId = 'androidx.build_info_test'
-                        artifactId = 'test'
-                        version = '0.0.1'
+            afterEvaluate {
+                publishing {
+                    publications {
+                        maven(MavenPublication) {
+                            groupId = 'androidx.build_info_test'
+                            artifactId = 'test'
+                            version = '0.0.1'
+                            from(components.release)
+                        }
                     }
-                }
-                publications.withType(MavenPublication) {
-                    CreateLibraryBuildInfoFileTaskKt.createBuildInfoTask(
-                        project,
-                        it,
-                        null,
-                        it.artifactId,
-                        project.provider { "fakeSha" }
-                    )
+                    publications.withType(MavenPublication) {
+                        CreateLibraryBuildInfoFileTaskKt.createBuildInfoTask(
+                            project,
+                            it,
+                            null,
+                            it.artifactId,
+                            project.provider { "fakeSha" }
+                        )
+                    }
                 }
             }
             """.trimIndent()
diff --git a/buildSrc/jetpad-integration/src/main/java/androidx/build/jetpad/LibraryBuildInfoFile.java b/buildSrc/jetpad-integration/src/main/java/androidx/build/jetpad/LibraryBuildInfoFile.java
index 55f5864..3458531 100644
--- a/buildSrc/jetpad-integration/src/main/java/androidx/build/jetpad/LibraryBuildInfoFile.java
+++ b/buildSrc/jetpad-integration/src/main/java/androidx/build/jetpad/LibraryBuildInfoFile.java
@@ -49,6 +49,7 @@
     public String projectZipPath;
     public Boolean groupIdRequiresSameVersion;
     public ArrayList<Dependency> dependencies;
+    public ArrayList<Dependency> dependencyConstraints;
     public ArrayList<Check> checks;
 
     /**
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index cca49a3..d373a4f 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -152,11 +152,6 @@
  */
 const val ALLOW_CUSTOM_COMPILE_SDK = "androidx.allowCustomCompileSdk"
 
-/**
- * If false, disable the CheckAarMetadata task. Default value is true.
- */
-const val CHECK_AAR_METADATA = "androidx.checkAarMetadata"
-
 val ALL_ANDROIDX_PROPERTIES = setOf(
     ADD_GROUP_CONSTRAINTS,
     ALTERNATIVE_PROJECT_URL,
@@ -184,8 +179,7 @@
     ENABLED_KMP_TARGET_PLATFORMS,
     ALLOW_MISSING_LINT_CHECKS_PROJECT,
     XCODEGEN_DOWNLOAD_URI,
-    ALLOW_CUSTOM_COMPILE_SDK,
-    CHECK_AAR_METADATA,
+    ALLOW_CUSTOM_COMPILE_SDK
 )
 
 /**
@@ -292,9 +286,3 @@
         s.toBoolean()
     }.orElse(false)
 }
-
-/**
- * Returns whether the `CheckAarMetadata` task should be enabled.
- */
-fun Project.isCheckAarMetadataEnabled() =
-    findBooleanProperty(CHECK_AAR_METADATA) ?: true
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 4b1a0cd..b7805a6 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -19,7 +19,6 @@
 import androidx.benchmark.gradle.BenchmarkPlugin
 import androidx.build.AndroidXImplPlugin.Companion.TASK_TIMEOUT_MINUTES
 import androidx.build.Release.DEFAULT_PUBLISH_CONFIG
-import androidx.build.SupportConfig.BUILD_TOOLS_VERSION
 import androidx.build.SupportConfig.COMPILE_SDK_VERSION
 import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
 import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
@@ -53,7 +52,6 @@
 import com.android.build.gradle.TestExtension
 import com.android.build.gradle.TestPlugin
 import com.android.build.gradle.TestedExtension
-import com.android.build.gradle.internal.tasks.CheckAarMetadataTask
 import com.android.build.gradle.internal.tasks.ListingFileRedirectTask
 import java.io.File
 import java.time.Duration
@@ -62,6 +60,7 @@
 import javax.inject.Inject
 import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
+import org.gradle.api.JavaVersion.VERSION_11
 import org.gradle.api.JavaVersion.VERSION_17
 import org.gradle.api.JavaVersion.VERSION_1_8
 import org.gradle.api.Plugin
@@ -139,13 +138,6 @@
                 task -> configureJvmTestTask(project, task)
         }
 
-        // Disable AAR verification in the platform branch until b/271291033 is fixed.
-        if (!project.isCheckAarMetadataEnabled()) {
-            project.tasks.withType(CheckAarMetadataTask::class.java).configureEach { task ->
-                task.enabled = false
-            }
-        }
-
         project.configureTaskTimeouts()
         project.configureMavenArtifactUpload(extension, componentFactory)
         project.configureExternalDependencyLicenseCheck()
@@ -282,7 +274,9 @@
     ) {
         project.afterEvaluate {
             project.tasks.withType(KotlinCompile::class.java).configureEach { task ->
-                if (extension.type.compilationTarget == CompilationTarget.HOST &&
+                if (extension.type == LibraryType.COMPILER_PLUGIN) {
+                    task.kotlinOptions.jvmTarget = "11"
+                } else if (extension.type.compilationTarget == CompilationTarget.HOST &&
                     extension.type != LibraryType.ANNOTATION_PROCESSOR_UTILS
                 ) {
                     task.kotlinOptions.jvmTarget = "17"
@@ -299,14 +293,6 @@
                 task.kotlinOptions.freeCompilerArgs += kotlinCompilerArgs
             }
 
-            // If no one else is going to register a source jar, then we should.
-            // This cross-plugin hands-off logic shouldn't be necessary once we clean up sourceSet
-            // logic (b/235828421)
-            if (!project.plugins.hasPlugin(LibraryPlugin::class.java) &&
-                !project.plugins.hasPlugin(JavaPlugin::class.java)) {
-                project.configureSourceJarForJava()
-            }
-
             val isAndroidProject = project.plugins.hasPlugin(LibraryPlugin::class.java) ||
                 project.plugins.hasPlugin(AppPlugin::class.java)
             // Explicit API mode is broken for Android projects
@@ -492,24 +478,21 @@
             androidXExtension
         )
 
-        // Disable AAR verification when we're forcing max dep versions.
-        if (project.usingMaxDepVersions()) {
-            project.tasks.withType(CheckAarMetadataTask::class.java).configureEach { task ->
-                task.enabled = false
-            }
-        }
-
         project.addToProjectMap(androidXExtension)
     }
 
     private fun configureWithJavaPlugin(project: Project, extension: AndroidXExtension) {
         project.configureErrorProneForJava()
-        project.configureSourceJarForJava()
 
         // Force Java 1.8 source- and target-compatibility for all Java libraries.
         val javaExtension = project.extensions.getByType<JavaPluginExtension>()
         project.afterEvaluate {
-            if (extension.type.compilationTarget == CompilationTarget.HOST &&
+            if (extension.type == LibraryType.COMPILER_PLUGIN) {
+                javaExtension.apply {
+                    sourceCompatibility = VERSION_11
+                    targetCompatibility = VERSION_11
+                }
+            } else if (extension.type.compilationTarget == CompilationTarget.HOST &&
                 extension.type != LibraryType.ANNOTATION_PROCESSOR_UTILS
             ) {
                 javaExtension.apply {
@@ -522,6 +505,9 @@
                     targetCompatibility = VERSION_1_8
                 }
             }
+            if (!project.plugins.hasPlugin(KotlinBasePluginWrapper::class.java)) {
+                project.configureSourceJarForJava()
+            }
         }
 
         project.configureJavaCompilationWarnings(extension)
@@ -612,7 +598,7 @@
         }
 
         compileSdkVersion(COMPILE_SDK_VERSION)
-        buildToolsVersion = BUILD_TOOLS_VERSION
+        buildToolsVersion = SupportConfig.buildToolsVersion(project)
         defaultConfig.targetSdk = TARGET_SDK_VERSION
         ndkVersion = SupportConfig.NDK_VERSION
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
index f6c6252..6c1b432 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXMultiplatformExtension.kt
@@ -86,17 +86,6 @@
         } else { null }
     }
 
-    @JvmOverloads
-    fun desktop(
-        block: Action<KotlinJvmTarget>? = null
-    ): KotlinJvmTarget? {
-        return if (project.enableJvm()) {
-            kotlinExtension.jvm("desktop") {
-                block?.execute(this)
-            }
-        } else { null }
-    }
-
     /**
      * Configures all mac targets supported by AndroidX.
      */
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
index 1531411..e2d0e2a 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -344,7 +344,7 @@
     val kotlinComponent = components.findByName("kotlin") as SoftwareComponentInternal
     withSourcesComponents(
         componentFactory,
-        setOf("sourcesElements", "androidxSourcesElements")
+        setOf("androidxSourcesElements")
     ) { sourcesComponents ->
         configure<PublishingExtension> {
             publications { pubs ->
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/Release.kt b/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
index bd9c72e..ea56dcb 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/Release.kt
@@ -241,10 +241,8 @@
             }
         }
         projectZipTask.configure { zipTask ->
-            if (!isPresubmitBuild()) {
-                zipTask.dependsOn(verifyInputs)
-                zipTask.finalizedBy(verifyOutputs)
-            }
+            zipTask.dependsOn(verifyInputs)
+            zipTask.finalizedBy(verifyOutputs)
             val verifyOutputsTask = verifyOutputs.get()
             verifyOutputsTask.addFile(zipTask.archiveFile.get().getAsFile())
         }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt b/buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
index 0ff1cef..35ea471 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
@@ -63,6 +63,18 @@
             it.duplicatesStrategy = DuplicatesStrategy.FAIL
         }
         registerSourcesVariant(sourceJar)
+
+        // b/272214715
+        configurations.whenObjectAdded {
+            if (it.name == "debugSourcesElements" || it.name == "releaseSourcesElements") {
+                it.artifacts.whenObjectAdded { _ ->
+                    it.attributes.attribute(
+                        DocsType.DOCS_TYPE_ATTRIBUTE,
+                        project.objects.named(DocsType::class.java, "fake-sources")
+                    )
+                }
+            }
+        }
     }
     project.afterEvaluate {
         // we can only tell if a project is multiplatform after it is configured
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
index 3cb172a..e16b300 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
@@ -206,11 +206,6 @@
 
     // Don't check Hilt compile-only configurations
     if (name.startsWith("hiltCompileOnly")) return false
-
-    // Don't check Desktop configurations since we don't publish them anyway
-    if (name.startsWith("desktop")) return false
-    if (name.startsWith("skiko")) return false
-
     return true
 }
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTask.kt
index 03f53c7..d7c4c07 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/buildInfo/CreateLibraryBuildInfoFileTask.kt
@@ -156,9 +156,8 @@
         libraryBuildInfoFile.projectZipPath = projectZipPath.get()
         libraryBuildInfoFile.kotlinVersion = kotlinVersion.orNull
         libraryBuildInfoFile.checks = ArrayList()
-        libraryBuildInfoFile.dependencies = ArrayList(
-            dependencyList.get() + dependencyConstraintList.get()
-        )
+        libraryBuildInfoFile.dependencies = ArrayList(dependencyList.get())
+        libraryBuildInfoFile.dependencyConstraints = ArrayList(dependencyConstraintList.get())
         return libraryBuildInfoFile
     }
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
index 2b4d9f1..feb0a6f 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt
@@ -556,7 +556,6 @@
             // placeholder test project to ensure no failure due to no instrumentation.
             // We can eventually remove if we resolve b/127819369
             ":placeholder-tests",
-            ":buildSrc-tests:project-subsets"
         )
 
         // Some tests are codependent even if their modules are not. Enable manual bundling of tests
@@ -639,6 +638,12 @@
                 ":constraintlayout:constraintlayout-compose:integration-tests",
                 ":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark",
                 ":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark-target"
+            ),
+            setOf(
+                ":profileinstaller:integration-tests:profile-verification",
+                ":profileinstaller:integration-tests:profile-verification-sample",
+                ":profileinstaller:integration-tests:profile-verification-sample-no-initializer",
+                ":benchmark:integration-tests:baselineprofile-consumer",
             )
         )
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
index cab8d67..25452de 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXDocsImplPlugin.kt
@@ -98,7 +98,7 @@
                 is LibraryPlugin -> {
                     val libraryExtension = project.extensions.getByType<LibraryExtension>()
                     libraryExtension.compileSdkVersion = SupportConfig.COMPILE_SDK_VERSION
-                    libraryExtension.buildToolsVersion = SupportConfig.BUILD_TOOLS_VERSION
+                    libraryExtension.buildToolsVersion = SupportConfig.buildToolsVersion(project)
 
                     // Use a local debug keystore to avoid build server issues.
                     val debugSigningConfig = libraryExtension.signingConfigs.getByName("debug")
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXKmpDocsImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXKmpDocsImplPlugin.kt
index d6a11f1..b3be53b 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXKmpDocsImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/docs/AndroidXKmpDocsImplPlugin.kt
@@ -23,7 +23,6 @@
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
-import org.gradle.api.attributes.Category
 import org.gradle.api.attributes.LibraryElements
 import org.gradle.api.model.ObjectFactory
 import org.gradle.api.tasks.bundling.Zip
@@ -95,10 +94,6 @@
                     LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
                     objectFactory.named(ATTRIBUTE_NAME)
                 )
-                it.attribute(
-                    Category.CATEGORY_ATTRIBUTE,
-                    objectFactory.named(Category.DOCUMENTATION)
-                )
             }
         }
     }
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 064552a..8832acb 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
@@ -72,6 +72,13 @@
     override fun execute() {
         val outputStream = ByteArrayOutputStream()
         var successful = false
+        val k2UastArg = listOfNotNull(
+            // Enable Android Lint infrastructure used by Metalava to use K2 UAST
+            // (also historically known as FIR) when running Metalava for this module.
+            "--Xuse-k2-uast".takeIf {
+                parameters.k2UastEnabled.get()
+            }
+        )
         try {
             execOperations.javaexec {
                 // Intellij core reflects into java.util.ResourceBundle
@@ -79,14 +86,9 @@
                     "--add-opens",
                     "java.base/java.util=ALL-UNNAMED"
                 )
-                if (parameters.k2UastEnabled.get()) {
-                    // Enable Android Lint infrastructure used by Metalava to use K2 UAST
-                    // (also historically known as FIR) when running Metalava for this module.
-                    it.systemProperty("lint.use.fir.uast", true)
-                }
                 it.classpath(parameters.metalavaClasspath.get())
                 it.mainClass.set("com.android.tools.metalava.Driver")
-                it.args = parameters.args.get()
+                it.args = parameters.args.get() + k2UastArg
                 it.setStandardOutput(outputStream)
                 it.setErrorOutput(outputStream)
             }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
index ec77a46..4b9fe1c 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/studio/StudioTask.kt
@@ -16,9 +16,14 @@
 
 package androidx.build.studio
 
+import androidx.build.OperatingSystem
 import androidx.build.ProjectLayoutType
+import androidx.build.getOperatingSystem
+import androidx.build.getSdkPath
 import androidx.build.getSupportRootFolder
 import androidx.build.getVersionByName
+import androidx.build.hasSupportRootFolder
+import androidx.build.setSupportRootFolder
 import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
 import java.io.File
 import java.nio.file.Files
@@ -170,6 +175,56 @@
     }
 
     /**
+     * Attempts to symlink the system-images and emulator SDK directories to a canonical SDK.
+     */
+    private fun setupSymlinksIfNeeded() {
+        val paths = listOf("system-images", "emulator")
+
+        // The support root folder may not have been set yet, in which case we'll optimistically
+        // assume that it matches the root project. This won't work for ui or Playground, but we'll
+        // fail gracefully later.
+        val hadSupportRootFolder = project.hasSupportRootFolder()
+        if (!hadSupportRootFolder) {
+            project.setSupportRootFolder(project.rootDir)
+        }
+        val localSdkPath = project.getSdkPath()
+        if (!hadSupportRootFolder) {
+            project.setSupportRootFolder(null)
+        }
+        if (!localSdkPath.exists()) {
+            // We probably got the support root folder wrong. Fail gracefully.
+            return
+        }
+
+        val relativeSdkPath = when (val osType = getOperatingSystem()) {
+            OperatingSystem.MAC -> "Library/Android/sdk"
+            OperatingSystem.LINUX -> "Android/Sdk"
+            else -> {
+                println("Failed to locate canonical SDK, unsupported operating system: $osType")
+                return
+            }
+        }
+
+        val canonicalSdkPath = File(File(System.getProperty("user.home")).parent, relativeSdkPath)
+        if (!canonicalSdkPath.exists()) {
+            // In the future, we might want to try a little harder to locate a canonical SDK path.
+            println("Failed to locate canonical SDK, not found at: $canonicalSdkPath")
+            return
+        }
+
+        paths.forEach { path ->
+            val link = File(localSdkPath, path)
+            val target = File(canonicalSdkPath, path)
+            if (!target.exists()) {
+                println("Skipping canonical SDK symlink creation, not found at: $target")
+            } else if (!link.exists()) {
+                println("Creating canonical SDK symlink for $target...")
+                Files.createSymbolicLink(link.toPath(), target.toPath())
+            }
+        }
+    }
+
+    /**
      * Launches Studio if the user accepts / has accepted the license agreement.
      */
     private fun launch() {
@@ -184,6 +239,10 @@
                     """.trimIndent()
                 )
             }
+
+            // This seems like as good a time as any to set up SDK symlinks...
+            setupSymlinksIfNeeded()
+
             println("Launching studio...")
             launchStudio()
         } else {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/transform/ConfigureAarAsJar.kt b/buildSrc/private/src/main/kotlin/androidx/build/transform/ConfigureAarAsJar.kt
index 1b04cf7..590be01 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/transform/ConfigureAarAsJar.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/transform/ConfigureAarAsJar.kt
@@ -20,7 +20,6 @@
 import org.gradle.api.Project
 import org.gradle.api.attributes.Attribute
 import org.gradle.api.attributes.Usage
-import org.gradle.api.attributes.java.TargetJvmEnvironment
 
 /**
  * Creates `testAarAsJar` configuration that can be used for JVM tests that need to Android library
@@ -57,11 +56,4 @@
     project.configurations.getByName(configurationName).dependencies.add(
         project.dependencies.create(aarAsJar)
     )
-
-    // Added to allow the :external:paparazzi:paparazzi build to select the correct jar (not get
-    // confused by the mpp jars) when the mpp builds are enabled
-    project.configurations.getByName(testAarsAsJars.name).attributes.attribute(
-        TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
-        project.objects.named(TargetJvmEnvironment::class.java, TargetJvmEnvironment.ANDROID)
-    )
 }
\ No newline at end of file
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
index bc4fc47..66d49df 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
@@ -147,7 +147,12 @@
     // https://github.com/gradle/gradle/issues/11203
     "partiallyDejetifyArchive",
     "stripArchiveForPartialDejetification",
-    "createArchive"
+    "createArchive",
+
+    // b/275795136
+    ":room:integration-tests:room-testapp-kotlin:kspWithKspGenJavaDebugAndroidTestKotlin",
+    // b/275795136
+    ":room:integration-tests:room-testapp-kotlin:kspWithKspGenKotlinDebugAndroidTestKotlin"
 )
 
 val DONT_TRY_RERUNNING_TASK_TYPES = setOf(
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt b/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
index 7961e09..802d8ef 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/KmpPlatforms.kt
@@ -31,11 +31,10 @@
     // https://blog.jetbrains.com/kotlin/2021/10/important-ua-parser-js-exploit-and-kotlin-js/
     JS,
     MAC,
-    LINUX,
-    DESKTOP;
+    LINUX;
     companion object {
         val native = listOf(MAC, LINUX)
-        val enabledByDefault = listOf(JVM, DESKTOP)
+        val enabledByDefault = listOf(JVM)
         private const val JVM_PLATFORM = "jvm"
         private const val JS_PLATFORM = "js"
         private const val MAC_ARM_64 = "macosarm64"
@@ -44,7 +43,6 @@
         private const val IOS_SIMULATOR_ARM_64 = "iossimulatorarm64"
         private const val IOS_X_64 = "iosx64"
         private const val IOS_ARM_64 = "iosarm64"
-        private const val DESKTOP_PLATFORM = "desktop"
         val macPlatforms = listOf(MAC_ARM_64, MAC_OSX_64)
         val linuxPlatforms = listOf(LINUX_64)
         val iosPlatforms = listOf(IOS_SIMULATOR_ARM_64, IOS_ARM_64, IOS_X_64)
@@ -90,5 +88,4 @@
 fun Project.enableLinux(): Boolean =
     enabledKmpPlatforms().contains(KmpPlatform.LINUX) || Multiplatform.isKotlinNativeEnabled(this)
 fun Project.enableJvm(): Boolean = enabledKmpPlatforms().contains(KmpPlatform.JVM)
-fun Project.enableDesktop(): Boolean = enabledKmpPlatforms().contains(KmpPlatform.DESKTOP)
 fun Project.enableNative(): Boolean = enableMac() && enableLinux()
\ No newline at end of file
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt b/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
index 554c2fdf..326c96f 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
@@ -40,7 +40,6 @@
         @JvmStatic
         fun isKotlinNativeEnabled(project: Project): Boolean {
             return "KMP".equals(System.getenv()["ANDROIDX_PROJECTS"], ignoreCase = true) ||
-                "INFRAROGUE".equals(System.getenv()["ANDROIDX_PROJECTS"], ignoreCase = true) ||
                 ProjectLayoutType.isPlayground(project) ||
                 project.providers.gradleProperty("androidx.kmp.native.enabled")
                     .orNull?.toBoolean() == true
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
index 8de139c..3b778ce 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
@@ -126,7 +126,7 @@
 /**
  * Sets the path to the canonical root project directory, e.g. {@code frameworks/support}.
  */
-fun Project.setSupportRootFolder(rootDir: File) {
+fun Project.setSupportRootFolder(rootDir: File?) {
     val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
     return extension.set("supportRootFolder", rootDir)
 }
@@ -143,6 +143,14 @@
 }
 
 /**
+ * Returns whether the path to the canonical root project directory has been set.
+ */
+fun Project.hasSupportRootFolder(): Boolean {
+    val extension = project.rootProject.property("ext") as ExtraPropertiesExtension
+    return extension.has("supportRootFolder")
+}
+
+/**
  * Returns the path to the checkout's root directory, e.g. where {@code repo init} was run.
  * <p>
  * This method assumes that the canonical root project directory is {@code frameworks/support}.
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
index 439f4c9..35a8575 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt
@@ -28,6 +28,7 @@
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.RegularFileProperty
 import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.api.provider.Property
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.OutputDirectory
@@ -57,7 +58,7 @@
     val compileSdkVersion: String = SupportConfig.COMPILE_SDK_VERSION
 
     @get:Input
-    val buildToolsVersion: String = SupportConfig.BUILD_TOOLS_VERSION
+    abstract val buildToolsVersion: Property<String>
 
     @get:Input
     val minSdkVersion: Int = SupportConfig.DEFAULT_MIN_SDK_VERSION
@@ -109,7 +110,7 @@
             writer.write("navigationRuntime=$navigationRuntime\n")
             writer.write("kotlinStdlib=$kotlinStdlib\n")
             writer.write("compileSdkVersion=$compileSdkVersion\n")
-            writer.write("buildToolsVersion=$buildToolsVersion\n")
+            writer.write("buildToolsVersion=${buildToolsVersion.get()}\n")
             writer.write("minSdkVersion=$minSdkVersion\n")
             writer.write("kotlinVersion=$kotlinVersion\n")
             writer.write("kspVersion=$kspVersion\n")
@@ -136,6 +137,11 @@
                     project.getRepositoryDirectory().toRelativeString(project.projectDir)
                 it.debugKeystore.set(project.getKeystore())
                 it.outputDir.set(generatedDirectory)
+                it.buildToolsVersion.set(
+                    project.provider {
+                        SupportConfig.buildToolsVersion(project)
+                    }
+                )
                 it.buildSrcOutRelativePath =
                     (project.properties["buildSrcOut"] as File).toRelativeString(project.projectDir)
                 // Copy repositories used for the library project so that it can replicate the same
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
index f3b7ee8..de3d495 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -24,7 +24,8 @@
 object SupportConfig {
     const val DEFAULT_MIN_SDK_VERSION = 14
     const val INSTRUMENTATION_RUNNER = "androidx.test.runner.AndroidJUnitRunner"
-    const val BUILD_TOOLS_VERSION = "33.0.1"
+    private const val INTERNAL_BUILD_TOOLS_VERSION = "34.0.0-rc3"
+    private const val PUBLIC_BUILD_TOOLS_VERSION = "33.0.1"
     const val NDK_VERSION = "23.1.7779620"
 
     /**
@@ -47,6 +48,20 @@
      * set to a pre-release version, tests will only be able to run on pre-release devices.
      */
     const val TARGET_SDK_VERSION = 33
+
+    /**
+     * Returns the build tools version that should be used for the project.
+     *
+     * Note that the value might be different between the internal and external (github) builds.
+     */
+    @JvmStatic
+    fun buildToolsVersion(project: Project): String {
+        return if (ProjectLayoutType.isPlayground(project)) {
+            PUBLIC_BUILD_TOOLS_VERSION
+        } else {
+            INTERNAL_BUILD_TOOLS_VERSION
+        }
+    }
 }
 
 fun Project.getExternalProjectPath(): File {
diff --git a/busytown/androidx.sh b/busytown/androidx.sh
index 41a723a..621ff22 100755
--- a/busytown/androidx.sh
+++ b/busytown/androidx.sh
@@ -22,7 +22,6 @@
       -Pandroidx.enableComposeCompilerMetrics=true \
       -Pandroidx.enableComposeCompilerReports=true \
       -Pandroidx.constraints=true \
-      -Pandroidx.enabled.kmp.target.platforms=-desktop \
       --no-daemon \
       --profile "$@"; then
     EXIT_VALUE=1
diff --git a/busytown/androidx_compose_multiplatform.sh b/busytown/androidx_compose_multiplatform.sh
index c19ca1a..5f39449 100755
--- a/busytown/androidx_compose_multiplatform.sh
+++ b/busytown/androidx_compose_multiplatform.sh
@@ -7,3 +7,12 @@
 export USE_ANDROIDX_REMOTE_BUILD_CACHE=gcp
 export ANDROIDX_PROJECTS=COMPOSE
 
+
+# b/235340662 don't verify dependency versions because we cannot pin to multiplatform deps
+./androidx.sh \
+  -Pandroidx.compose.multiplatformEnabled=true \
+  compileDebugAndroidTestSources \
+  compileDebugSources \
+  desktopTestClasses \
+  -x verifyDependencyVersions  \
+  -Pandroidx.enableAffectedModuleDetection=false "$@"
diff --git a/busytown/androidx_max_dep_versions.sh b/busytown/androidx_max_dep_versions.sh
index 72c6665..ca9e1d1 100755
--- a/busytown/androidx_max_dep_versions.sh
+++ b/busytown/androidx_max_dep_versions.sh
@@ -7,6 +7,7 @@
 
 impl/build.sh assembleRelease assembleAndroidTest \
     -Pandroidx.useMaxDepVersions \
+    -Dandroid.experimental.disableCompileSdkChecks=true \
     "$@"
 
 echo "Completing $0 at $(date)"
diff --git a/busytown/androidx_multiplatform_host_tests_mac.sh b/busytown/androidx_multiplatform_host_tests_mac.sh
index 0dce2a4..8da2ed5 100755
--- a/busytown/androidx_multiplatform_host_tests_mac.sh
+++ b/busytown/androidx_multiplatform_host_tests_mac.sh
@@ -6,7 +6,7 @@
 
 # Must be run on Mac
 
-export ANDROIDX_PROJECTS=INFRAROGUE   # TODO: Switch from `INFRAROGUE` to `KMP`
+export ANDROIDX_PROJECTS=KMP
 
 # disable GCP cache, these machines don't have credentials.
 export USE_ANDROIDX_REMOTE_BUILD_CACHE=false
@@ -24,4 +24,4 @@
     -Pandroidx.displayTestOutput=false \
     "$@"
 
-echo "Completing $0 at $(date)"
+echo "Completing $0 at $(date)"
\ No newline at end of file
diff --git a/busytown/androidx_multiplatform_linux.sh b/busytown/androidx_multiplatform_linux.sh
index 890c57b..3f9d518 100755
--- a/busytown/androidx_multiplatform_linux.sh
+++ b/busytown/androidx_multiplatform_linux.sh
@@ -2,7 +2,8 @@
 set -e
 cd "$(dirname $0)"
 
-# Builds all projects that support KMP
+# Builds all projects that support KMP except for Compose-specific projects which are already
+# covered by androidx_compose_multiplatform.sh
 
 # Must be run on Linux
 
diff --git a/busytown/androidx_multiplatform_mac.sh b/busytown/androidx_multiplatform_mac.sh
index 3373b9d..9f2dfbd 100755
--- a/busytown/androidx_multiplatform_mac.sh
+++ b/busytown/androidx_multiplatform_mac.sh
@@ -7,7 +7,7 @@
 
 # Must be run on Mac
 
-export ANDROIDX_PROJECTS=INFRAROGUE   # TODO: Switch from `INFRAROGUE` to `KMP`
+export ANDROIDX_PROJECTS=KMP
 
 # disable GCP cache, these machines don't have credentials.
 export USE_ANDROIDX_REMOTE_BUILD_CACHE=false
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/Camera2CameraControlDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/Camera2CameraControlDeviceTest.kt
index 2ce4722..d0fa9e3 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/Camera2CameraControlDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/Camera2CameraControlDeviceTest.kt
@@ -68,6 +68,7 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
 import org.junit.After
 import org.junit.Assert
 import org.junit.Assume
@@ -110,9 +111,11 @@
     }
 
     @After
-    fun tearDown() {
+    fun tearDown(): Unit = runBlocking {
         if (::camera.isInitialized) {
-            camera.detachUseCases()
+            withContext(Dispatchers.Main) {
+                camera.removeUseCases(camera.useCases)
+            }
         }
 
         CameraXUtil.shutdown()[10000, TimeUnit.MILLISECONDS]
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
index e05e88e..3ce18a3 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/CameraControlAdapterDeviceTest.kt
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AE
 import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AF
 import android.hardware.camera2.CameraCharacteristics.CONTROL_MAX_REGIONS_AWB
+import android.hardware.camera2.CameraDevice
 import android.hardware.camera2.CameraMetadata.CONTROL_AE_MODE_OFF
 import android.hardware.camera2.CameraMetadata.CONTROL_AE_MODE_ON
 import android.hardware.camera2.CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH
@@ -38,8 +39,7 @@
 import android.hardware.camera2.CaptureRequest.CONTROL_AF_MODE
 import android.hardware.camera2.CaptureRequest.CONTROL_AF_REGIONS
 import android.hardware.camera2.CaptureRequest.CONTROL_AWB_REGIONS
-import android.hardware.camera2.CaptureRequest.CONTROL_CAPTURE_INTENT
-import android.hardware.camera2.CaptureRequest.CONTROL_CAPTURE_INTENT_CUSTOM
+import android.hardware.camera2.CaptureRequest.CONTROL_EFFECT_MODE
 import android.hardware.camera2.CaptureRequest.CONTROL_ZOOM_RATIO
 import android.hardware.camera2.CaptureRequest.FLASH_MODE
 import android.hardware.camera2.CaptureRequest.FLASH_MODE_TORCH
@@ -47,14 +47,21 @@
 import android.hardware.camera2.params.MeteringRectangle
 import android.os.Build
 import android.util.Size
+import android.view.Surface
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.FrameInfo
 import androidx.camera.camera2.pipe.RequestMetadata
 import androidx.camera.camera2.pipe.integration.adapter.CameraControlAdapter
+import androidx.camera.camera2.pipe.integration.compat.quirk.CrashWhenTakingPhotoWithAutoFlashAEModeQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.DeviceQuirks
+import androidx.camera.camera2.pipe.integration.compat.quirk.ImageCaptureFailWithAutoFlashQuirk
+import androidx.camera.camera2.pipe.integration.compat.workaround.AutoFlashAEModeDisablerImpl
 import androidx.camera.camera2.pipe.integration.impl.ComboRequestListener
+import androidx.camera.camera2.pipe.integration.interop.Camera2CameraInfo
 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
 import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
 import androidx.camera.camera2.pipe.testing.VerifyResultListener
+import androidx.camera.core.Camera
 import androidx.camera.core.CameraControl
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.FocusMeteringAction
@@ -63,12 +70,17 @@
 import androidx.camera.core.Preview
 import androidx.camera.core.SurfaceOrientedMeteringPointFactory
 import androidx.camera.core.UseCase
+import androidx.camera.core.impl.CameraInfoInternal
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.Quirks
+import androidx.camera.core.impl.SessionConfig
+import androidx.camera.core.impl.utils.futures.Futures
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CameraXUtil
 import androidx.camera.testing.SurfaceTextureProvider
-import androidx.camera.video.Recorder
-import androidx.camera.video.VideoCapture
+import androidx.camera.testing.fakes.FakeUseCase
+import androidx.camera.testing.fakes.FakeUseCaseConfig
 import androidx.concurrent.futures.await
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -107,6 +119,7 @@
     private lateinit var comboListener: ComboRequestListener
     private lateinit var characteristics: CameraCharacteristics
     private var hasFlashUnit: Boolean = false
+    private var testEffectMode: Int? = null
 
     private val imageCapture = ImageCapture.Builder().build()
     private val imageAnalysis = ImageAnalysis.Builder().build().apply {
@@ -141,16 +154,15 @@
             CameraSelector.LENS_FACING_BACK
         )!!
 
-        hasFlashUnit = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE).let {
-            it != null && it
-        }
+        hasFlashUnit = camera.cameraInfo.hasFlashUnit()
+        testEffectMode = camera.getTestEffectMode()
     }
 
     @After
     fun tearDown(): Unit = runBlocking {
         if (::camera.isInitialized) {
             withContext(Dispatchers.Main) {
-                camera.detachUseCases()
+                camera.removeUseCases(camera.useCases)
             }
         }
 
@@ -179,7 +191,6 @@
 
     // TODO: test all public API of the CameraControl to ensure the RequestOptions still exist
     //  after adding/removing the UseCase.
-    @SdkSuppress(minSdkVersion = 22) // b/266740827
     @Test
     fun removeUseCase_requestOptionsShouldSetToCamera(): Unit = runBlocking {
         // Arrange.
@@ -381,7 +392,7 @@
 
     @Test
     fun setTemplateRecord_afModeToContinuousVideo() = runBlocking {
-        bindUseCase(createVideoCapture())
+        bindUseCase(createFakeRecordingUseCase())
 
         // Assert. Verify the afMode.
         waitForResult(captureCount = 60).verify(
@@ -392,10 +403,10 @@
         )
     }
 
-    @SdkSuppress(minSdkVersion = 22) // b/266740827
     @Test
     fun setZoomRatio_operationCanceledExceptionIfNoUseCase() {
-        assertFutureFailedWithOperationCancellation(cameraControl.setZoomRatio(1.5f))
+        val ratio = camera.getMaxSupportedZoomRatio()
+        assertFutureFailedWithOperationCancellation(cameraControl.setZoomRatio(ratio))
     }
 
     private fun <T> assertFutureFailedWithOperationCancellation(future: ListenableFuture<T>) {
@@ -408,18 +419,20 @@
     }
 
     private fun CameraCharacteristics.getMaxRegionCount(
-        option_max_regions: CameraCharacteristics.Key<Int>
-    ) = get(option_max_regions) ?: 0
+        optionMaxRegions: CameraCharacteristics.Key<Int>
+    ) = get(optionMaxRegions) ?: 0
 
     private suspend fun arrangeRequestOptions() {
         cameraControl.setExposureCompensationIndex(1)
-        cameraControl.setZoomRatio(1.0f)
-        cameraControl.camera2cameraControl.setCaptureRequestOptions(
-            CaptureRequestOptions.Builder().setCaptureRequestOption(
-                CONTROL_CAPTURE_INTENT,
-                CONTROL_CAPTURE_INTENT_CUSTOM
-            ).build()
-        ).await()
+        cameraControl.setZoomRatio(camera.getMaxSupportedZoomRatio())
+        testEffectMode?.let { effectMode ->
+            cameraControl.camera2cameraControl.setCaptureRequestOptions(
+                CaptureRequestOptions.Builder().setCaptureRequestOption(
+                    CONTROL_EFFECT_MODE,
+                    effectMode
+                ).build()
+            ).await()
+        }
 
         // Ensure the requests are already set to the CaptureRequest.
         waitForResult().verify(
@@ -432,11 +445,13 @@
                 )
 
                 // Ensure the Camera2Interop working before testing
-                assumeThat(
-                    "Camera2Interop Request doesn't set to CaptureRequest, ignore the test",
-                    captureRequest.request[CONTROL_CAPTURE_INTENT],
-                    equalTo(CONTROL_CAPTURE_INTENT_CUSTOM)
-                )
+                if (testEffectMode != null) {
+                    assumeThat(
+                        "Camera2Interop Request doesn't set to CaptureRequest, ignore the test",
+                        captureRequest.request[CONTROL_EFFECT_MODE],
+                        equalTo(testEffectMode)
+                    )
+                }
 
                 // Ensure the Zoom working before testing
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -458,19 +473,29 @@
         )
     }
 
+    private fun Camera.getTestEffectMode(): Int? {
+        return Camera2CameraInfo.from(cameraInfo)
+            .getCameraCharacteristic(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS)?.getOrNull(0)
+    }
+
+    private fun Camera.getMaxSupportedZoomRatio(): Float {
+        return cameraInfo.zoomState.value!!.maxZoomRatio
+    }
+
     private suspend fun verifyRequestOptions() {
         waitForResult(captureCount = 30).verify(
             { metadata: RequestMetadata, _ ->
                 val checkEV = metadata.request[CONTROL_AE_EXPOSURE_COMPENSATION] == 1
-                val checkCaptureIntent =
-                    metadata.request[CONTROL_CAPTURE_INTENT] == CONTROL_CAPTURE_INTENT_CUSTOM
+                val checkEffectMode = testEffectMode?.let {
+                    metadata.request[CONTROL_EFFECT_MODE] == it
+                } ?: true
                 val checkZoom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                     metadata.request[CONTROL_ZOOM_RATIO] != null
                 } else {
                     metadata.request[SCALER_CROP_REGION] != null
                 }
 
-                checkEV && checkCaptureIntent && checkZoom
+                checkEV && checkEffectMode && checkZoom
             },
             TIMEOUT
         )
@@ -490,8 +515,52 @@
         cameraControl = camera.cameraControl as CameraControlAdapter
     }
 
-    private fun createVideoCapture(): VideoCapture<Recorder> {
-        return VideoCapture.withOutput(Recorder.Builder().build())
+    private fun createFakeRecordingUseCase(): FakeUseCase {
+        return FakeTestUseCase(
+            FakeUseCaseConfig.Builder().setTargetName("FakeRecordingUseCase").useCaseConfig
+        ).apply {
+            initAndActive()
+        }
+    }
+
+    private class FakeTestUseCase(config: FakeUseCaseConfig) : FakeUseCase(config) {
+
+        val deferrableSurface = object : DeferrableSurface() {
+            init {
+                terminationFuture.addListener(
+                    { cleanUp() }, Dispatchers.IO.asExecutor()
+                )
+            }
+
+            private val surfaceTexture = SurfaceTexture(0).also {
+                it.setDefaultBufferSize(640, 480)
+            }
+            val testSurface = Surface(surfaceTexture)
+
+            override fun provideSurface(): ListenableFuture<Surface> {
+                return Futures.immediateFuture(testSurface)
+            }
+
+            fun cleanUp() {
+                testSurface.release()
+                surfaceTexture.release()
+            }
+        }
+
+        fun initAndActive() {
+            val sessionConfigBuilder = SessionConfig.Builder().apply {
+                setTemplateType(CameraDevice.TEMPLATE_RECORD)
+                addSurface(deferrableSurface)
+            }
+
+            updateSessionConfig(sessionConfigBuilder.build())
+            notifyActive()
+        }
+
+        override fun onUnbind() {
+            super.onUnbind()
+            deferrableSurface.close()
+        }
     }
 
     private suspend fun createPreview(): Preview =
@@ -535,8 +604,14 @@
     }
 
     private fun RequestMetadata.isAeMode(aeMode: Int): Boolean {
-        return if (characteristics.isAeModeSupported(aeMode)) {
-            getOrDefault(CONTROL_AE_MODE, null) == aeMode
+        val aeQuirkEnabled =
+            camera.getCameraQuirks().contains(ImageCaptureFailWithAutoFlashQuirk::class.java) ||
+                DeviceQuirks[CrashWhenTakingPhotoWithAutoFlashAEModeQuirk::class.java] != null
+        val aeModeCorrected =
+            if (aeQuirkEnabled) AutoFlashAEModeDisablerImpl.getCorrectedAeMode(aeMode) else aeMode
+
+        return if (characteristics.isAeModeSupported(aeModeCorrected)) {
+            getOrDefault(CONTROL_AE_MODE, null) == aeModeCorrected
         } else {
             val fallbackMode =
                 if (characteristics.isAeModeSupported(CONTROL_AE_MODE_ON)) {
@@ -548,6 +623,10 @@
         }
     }
 
+    private fun Camera.getCameraQuirks(): Quirks {
+        return (cameraInfo as? CameraInfoInternal)?.cameraQuirks!!
+    }
+
     private fun CameraCharacteristics.isAfModeSupported(
         afMode: Int
     ) = (get(CONTROL_AF_AVAILABLE_MODES) ?: intArrayOf(-1)).contains(afMode)
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EncoderProfilesProviderAdapterDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EncoderProfilesProviderAdapterDeviceTest.kt
index e527c4b..9a81718 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EncoderProfilesProviderAdapterDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EncoderProfilesProviderAdapterDeviceTest.kt
@@ -192,13 +192,16 @@
     }
 
     private fun skipTestOnDevicesWithProblematicBuild() {
-        // Skip test for b/265613005 and b/223439995
+        // Skip test for b/265613005, b/223439995 and b/277174217
         val hasVideoProfilesQuirk = DeviceQuirks[InvalidVideoProfilesQuirk::class.java] != null
-        val isProblematicCuttlefishBuild =
-            Build.MODEL.contains("Cuttlefish") && Build.ID.startsWith("TP1A")
         Assume.assumeFalse(
             "Skip test with null VideoProfile issue. Unable to test.",
-            hasVideoProfilesQuirk || isProblematicCuttlefishBuild
+            hasVideoProfilesQuirk || isProblematicCuttlefishBuild()
         )
     }
+
+    private fun isProblematicCuttlefishBuild(): Boolean {
+        return Build.MODEL.contains("Cuttlefish", true) &&
+            (Build.ID.startsWith("TP1A", true) || Build.ID.startsWith("TSE4", true))
+    }
 }
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EvCompDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EvCompDeviceTest.kt
index fe02a63..092a7c6 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EvCompDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/EvCompDeviceTest.kt
@@ -43,6 +43,7 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
 import org.junit.After
 import org.junit.Assume
 import org.junit.Before
@@ -98,9 +99,11 @@
     }
 
     @After
-    fun tearDown() {
+    fun tearDown(): Unit = runBlocking {
         if (::camera.isInitialized) {
-            camera.detachUseCases()
+            withContext(Dispatchers.Main) {
+                camera.removeUseCases(camera.useCases)
+            }
         }
 
         CameraXUtil.shutdown()[10000, TimeUnit.MILLISECONDS]
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/TapToFocusDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/TapToFocusDeviceTest.kt
index e0efae0..0366575 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/TapToFocusDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/TapToFocusDeviceTest.kt
@@ -99,7 +99,7 @@
     fun tearDown(): Unit = runBlocking {
         withContext(Dispatchers.Main) {
             if (::camera.isInitialized) {
-                camera.detachUseCases()
+                camera.removeUseCases(camera.useCases)
             }
         }
 
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/UseCaseSurfaceManagerDeviceTest.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/UseCaseSurfaceManagerDeviceTest.kt
index b6ba0b18..0dd04bc 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/UseCaseSurfaceManagerDeviceTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/integration/UseCaseSurfaceManagerDeviceTest.kt
@@ -18,6 +18,7 @@
 
 package androidx.camera.camera2.pipe.integration
 
+import android.content.Context
 import android.content.Intent
 import android.graphics.ImageFormat
 import android.hardware.camera2.CameraDevice
@@ -27,8 +28,11 @@
 import android.os.HandlerThread
 import android.view.Surface
 import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraPipe
 import androidx.camera.camera2.pipe.CameraSurfaceManager
+import androidx.camera.camera2.pipe.integration.compat.workaround.InactiveSurfaceCloserImpl
 import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
+import androidx.camera.camera2.pipe.integration.impl.UseCaseSurfaceManager
 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
 import androidx.camera.camera2.pipe.testing.TestUseCaseCamera
 import androidx.camera.core.impl.DeferrableSurface
@@ -221,6 +225,35 @@
         assertThat(cameraClosedUsageCount).isEqualTo(1)
     }
 
+    @Test
+    fun closingUseCaseSurfaceManagerClosesDeferrableSurface() = runBlocking {
+        // Arrange.
+        testSessionParameters = TestSessionParameters()
+        val useCases = listOf(createFakeUseCase().apply {
+            setupSessionConfig(testSessionParameters.sessionConfig)
+        })
+
+        val context: Context = ApplicationProvider.getApplicationContext()
+        val cameraPipe = CameraPipe(CameraPipe.Config(context))
+        testUseCaseCamera = TestUseCaseCamera(
+            context = context,
+            cameraId = cameraId,
+            useCases = useCases,
+            threads = useCaseThreads,
+            cameraPipe = cameraPipe,
+            useCaseSurfaceManager = UseCaseSurfaceManager(
+                useCaseThreads, cameraPipe, InactiveSurfaceCloserImpl(),
+            )
+        )
+
+        // Act.
+        testUseCaseCamera.useCaseCameraGraphConfig.graph.close()
+        testUseCaseCamera.useCaseSurfaceManager.stopAsync().awaitWithTimeout()
+
+        // Assert, verify the DeferrableSurface is closed.
+        assertThat(testSessionParameters.deferrableSurface.isClosed).isTrue()
+    }
+
     private fun createFakeUseCase() = object : FakeUseCase(
         FakeUseCaseConfig.Builder().setTargetName("UseCase").useCaseConfig
     ) {
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
index 6b9b502..d5795f9 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
@@ -30,6 +30,7 @@
 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
 import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
+import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpInactiveSurfaceCloser
 import androidx.camera.camera2.pipe.integration.config.CameraConfig
 import androidx.camera.camera2.pipe.integration.config.UseCaseCameraConfig
 import androidx.camera.camera2.pipe.integration.impl.CameraCallbackMap
@@ -64,10 +65,15 @@
     val useCaseSurfaceManager: UseCaseSurfaceManager = UseCaseSurfaceManager(
         threads,
         cameraPipe,
+        NoOpInactiveSurfaceCloser,
     ),
 ) : UseCaseCamera {
     val useCaseCameraGraphConfig =
-        UseCaseCameraConfig(useCases, CameraStateAdapter()).provideUseCaseGraphConfig(
+        UseCaseCameraConfig(
+            useCases,
+            CameraStateAdapter(),
+            CameraGraph.Flags()
+        ).provideUseCaseGraphConfig(
             callbackMap = callbackMap,
             cameraConfig = cameraConfig,
             cameraPipe = cameraPipe,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
index c929ca0..c7f1e59 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInternalAdapter.kt
@@ -70,7 +70,6 @@
     }
 
     override fun release(): ListenableFuture<Void> {
-        // TODO(b/185207100): Implement when CameraState is ready.
         return threads.scope.launch { useCaseManager.close() }.asListenableFuture()
     }
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
index ccf2838..2b1d488 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraSurfaceAdapter.kt
@@ -23,6 +23,8 @@
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraPipe
+import androidx.camera.camera2.pipe.DoNotDisturbException
+import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.core.Log.debug
 import androidx.camera.camera2.pipe.integration.config.CameraAppComponent
 import androidx.camera.core.impl.AttachedSurfaceInfo
@@ -43,7 +45,8 @@
     availableCameraIds: Set<String>
 ) : CameraDeviceSurfaceManager {
     private val component = cameraComponent as CameraAppComponent
-    private val supportedSurfaceCombinationMap = mutableMapOf<String, SupportedSurfaceCombination>()
+    private val supportedSurfaceCombinationMap =
+        mutableMapOf<String, SupportedSurfaceCombination?>()
 
     init {
         debug { "AvailableCameraIds = $availableCameraIds" }
@@ -59,14 +62,20 @@
         availableCameraIds: Set<String>
     ) {
         for (cameraId in availableCameraIds) {
-            val cameraMetadata =
-                component.getCameraDevices().awaitCameraMetadata(CameraId(cameraId))
-            supportedSurfaceCombinationMap[cameraId] =
-                SupportedSurfaceCombination(
+            try {
+                val cameraMetadata =
+                    component.getCameraDevices().awaitCameraMetadata(CameraId(cameraId))
+                supportedSurfaceCombinationMap[cameraId] = SupportedSurfaceCombination(
                     context,
                     checkNotNull(cameraMetadata),
                     EncoderProfilesProviderAdapter(cameraId)
                 )
+            } catch (exception: DoNotDisturbException) {
+                Log.error {
+                    "Failed to create supported surface combinations: " +
+                        "Do Not Disturb mode is on"
+                }
+            }
         }
     }
 
@@ -89,7 +98,8 @@
 
         return supportedSurfaceCombinationMap[cameraId]!!.transformSurfaceConfig(
             cameraMode,
-            imageFormat, size)
+            imageFormat, size
+        )
     }
 
     /**
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
index 825e6d9..bc9620f 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraUseCaseAdapter.kt
@@ -79,9 +79,6 @@
     ): Config? {
         debug { "Creating config for $captureType" }
 
-        // TODO: quirks for ImageCapture are not ready for the UseCaseConfigFactory. Will need to
-        //  move the quirk related item to this change.
-
         val mutableConfig = MutableOptionsBundle.create()
         val sessionBuilder = SessionConfig.Builder()
         when (captureType) {
@@ -138,7 +135,7 @@
             mutableConfig.insertOption(
                 OPTION_RESOLUTION_SELECTOR,
                 ResolutionSelector.Builder().setResolutionStrategy(
-                    ResolutionStrategy.create(
+                    ResolutionStrategy(
                         previewSize,
                         ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER
                     )
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CaptureConfigAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CaptureConfigAdapter.kt
index 83224a4..b40b49f 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CaptureConfigAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CaptureConfigAdapter.kt
@@ -59,9 +59,6 @@
             "Attempted to issue a capture without surfaces using $captureConfig"
         }
 
-        // TODO(b/212202121): Checks and attaches repeating surface to the request if there's
-        //  no surface has been already attached.
-
         val streamIdList = surfaces.map {
             checkNotNull(useCaseGraphConfig.surfaceToStreamMap[it]) {
                 "Attempted to issue a capture with an unrecognized surface."
@@ -97,8 +94,6 @@
             )
         }
 
-        // TODO(b/212213092): Apply AeModeQuirk.
-
         return Request(
             streams = streamIdList,
             listeners = listOf(callbacks),
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
index 6b1226e..9165244 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
@@ -170,8 +170,10 @@
         imageFormat: Int,
         size: Size
     ): SurfaceConfig {
-        return SurfaceConfig.transformSurfaceConfig(cameraMode,
-            imageFormat, size, getUpdatedSurfaceSizeDefinitionByFormat(imageFormat))
+        return SurfaceConfig.transformSurfaceConfig(
+            cameraMode,
+            imageFormat, size, getUpdatedSurfaceSizeDefinitionByFormat(imageFormat)
+        )
     }
 
     /**
@@ -505,9 +507,8 @@
      * @return Maximum supported video size.
      */
     private fun getRecordSizeFromStreamConfigurationMapCompat(): Size {
-        val map: StreamConfigurationMap =
-            streamConfigurationMapCompat.toStreamConfigurationMap()
-        val videoSizeArr = map.getOutputSizes(
+        val map = streamConfigurationMapCompat.toStreamConfigurationMap()
+        val videoSizeArr = map?.getOutputSizes(
             MediaRecorder::class.java
         ) ?: return RESOLUTION_480P
         Arrays.sort(videoSizeArr, CompareSizesByArea(true))
@@ -620,7 +621,7 @@
      */
     @SuppressLint("ClassVerificationFailure")
     internal fun getMaxOutputSizeByFormat(
-        map: StreamConfigurationMap,
+        map: StreamConfigurationMap?,
         imageFormat: Int,
         highResolutionIncluded: Boolean
     ): Size? {
@@ -631,9 +632,9 @@
                 // after Android level 23 but not public in Android L. Use {@link SurfaceTexture}
                 // or {@link MediaCodec} will finally mapped to 0x22 in StreamConfigurationMap to
                 // retrieve the output sizes information.
-                map.getOutputSizes(SurfaceTexture::class.java)
+                map?.getOutputSizes(SurfaceTexture::class.java)
             } else {
-                map.getOutputSizes(imageFormat)
+                map?.getOutputSizes(imageFormat)
             }
         if (outputSizes.isNullOrEmpty()) {
             return null
@@ -643,7 +644,7 @@
         var maxHighResolutionSize = SizeUtil.RESOLUTION_ZERO
 
         if (Build.VERSION.SDK_INT >= 23 && highResolutionIncluded) {
-            val highResolutionOutputSizes = map.getHighResolutionOutputSizes(imageFormat)
+            val highResolutionOutputSizes = map?.getHighResolutionOutputSizes(imageFormat)
             if (highResolutionOutputSizes != null && highResolutionOutputSizes.isNotEmpty()) {
                 maxHighResolutionSize =
                     Collections.max(highResolutionOutputSizes.asList(), compareSizesByArea)
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/CameraCompatModule.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/CameraCompatModule.kt
index 4c61ecc..49e9ebe 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/CameraCompatModule.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/CameraCompatModule.kt
@@ -20,6 +20,7 @@
 
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.integration.compat.workaround.AutoFlashAEModeDisabler
+import androidx.camera.camera2.pipe.integration.compat.workaround.InactiveSurfaceCloser
 import androidx.camera.camera2.pipe.integration.compat.workaround.MeteringRegionCorrection
 import androidx.camera.camera2.pipe.integration.compat.workaround.UseTorchAsFlash
 import dagger.Module
@@ -28,6 +29,7 @@
 @Module(
     includes = [
         AutoFlashAEModeDisabler.Bindings::class,
+        InactiveSurfaceCloser.Bindings::class,
         MeteringRegionCorrection.Bindings::class,
         UseTorchAsFlash.Bindings::class,
     ],
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompat.kt
index 128b3f7..5eb3edb 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompat.kt
@@ -22,6 +22,7 @@
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.config.CameraScope
+import androidx.camera.core.Logger
 import javax.inject.Inject
 
 /**
@@ -34,9 +35,13 @@
 @CameraScope
 @RequiresApi(21)
 class StreamConfigurationMapCompat @Inject constructor(
-    map: StreamConfigurationMap,
+    map: StreamConfigurationMap?,
     private val outputSizesCorrector: OutputSizesCorrector
 ) {
+    private val tag = "StreamConfigurationMapCompat"
+    private val cachedFormatOutputSizes = mutableMapOf<Int, Array<Size>>()
+    private val cachedFormatHighResolutionOutputSizes = mutableMapOf<Int, Array<Size>?>()
+    private val cachedClassOutputSizes = mutableMapOf<Class<*>, Array<Size>>()
     private var impl: StreamConfigurationMapCompatImpl
 
     init {
@@ -58,7 +63,21 @@
      * supported output
      */
     fun getOutputSizes(format: Int): Array<Size>? {
-        return outputSizesCorrector.applyQuirks(impl.getOutputSizes(format), format)
+        if (cachedFormatOutputSizes.contains(format)) {
+            return cachedFormatOutputSizes[format]?.clone()
+        }
+
+        val outputSizes = impl.getOutputSizes(format)
+
+        if (outputSizes.isNullOrEmpty()) {
+            Logger.w(tag, "Retrieved output sizes array is null or empty for format $format")
+            return outputSizes
+        }
+
+        outputSizesCorrector.applyQuirks(outputSizes, format).let {
+            cachedFormatOutputSizes[format] = it
+            return it.clone()
+        }
     }
 
     /**
@@ -68,17 +87,31 @@
      * Output sizes related quirks will be applied onto the returned sizes list.
      *
      * @param klass a non-`null` [Class] object reference
-     * @return an array of supported sizes for [ImageFormat.PRIVATE] format,
+     * @return an array of supported sizes for [ImageFormat#PRIVATE] format,
      * or `null` if the `klass` is not a supported output.
      * @throws NullPointerException if `klass` was `null`
      */
     fun <T> getOutputSizes(klass: Class<T>): Array<Size>? {
-        return outputSizesCorrector.applyQuirks<T>(impl.getOutputSizes<T>(klass), klass)
+        if (cachedClassOutputSizes.contains(klass)) {
+            return cachedClassOutputSizes[klass]?.clone()
+        }
+
+        val outputSizes = impl.getOutputSizes(klass)
+
+        if (outputSizes.isNullOrEmpty()) {
+            Logger.w(tag, "Retrieved output sizes array is null or empty for class $klass")
+            return outputSizes
+        }
+
+        outputSizesCorrector.applyQuirks(outputSizes, klass).let {
+            cachedClassOutputSizes[klass] = it
+            return it.clone()
+        }
     }
 
     /**
      * Get a list of supported high resolution sizes, which cannot operate at full
-     * [CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE] rate.
+     * [CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE] rate.
      *
      *
      * Output sizes related quirks will be applied onto the returned sizes list.
@@ -88,13 +121,25 @@
      * supported output
      */
     fun getHighResolutionOutputSizes(format: Int): Array<Size>? {
-        return outputSizesCorrector.applyQuirks(impl.getHighResolutionOutputSizes(format), format)
+        if (cachedFormatHighResolutionOutputSizes.contains(format)) {
+            return cachedFormatHighResolutionOutputSizes[format]?.clone()
+        }
+
+        var outputSizes = impl.getHighResolutionOutputSizes(format)
+
+        // High resolution output sizes can be null.
+        if (!outputSizes.isNullOrEmpty()) {
+            outputSizes = outputSizesCorrector.applyQuirks(outputSizes, format)
+        }
+
+        cachedFormatHighResolutionOutputSizes[format] = outputSizes
+        return outputSizes?.clone()
     }
 
     /**
      * Returns the [StreamConfigurationMap] represented by this object.
      */
-    fun toStreamConfigurationMap(): StreamConfigurationMap {
+    fun toStreamConfigurationMap(): StreamConfigurationMap? {
         return impl.unwrap()
     }
 
@@ -102,9 +147,10 @@
         fun getOutputSizes(format: Int): Array<Size>?
         fun <T> getOutputSizes(klass: Class<T>): Array<Size>?
         fun getHighResolutionOutputSizes(format: Int): Array<Size>?
+
         /**
          * Returns the underlying [StreamConfigurationMap] instance.
          */
-        fun unwrap(): StreamConfigurationMap
+        fun unwrap(): StreamConfigurationMap?
     }
 }
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatApi23Impl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatApi23Impl.kt
index 3bcbfd2..53b126f 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatApi23Impl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatApi23Impl.kt
@@ -21,13 +21,13 @@
 import androidx.annotation.RequiresApi
 
 @RequiresApi(23)
-internal class StreamConfigurationMapCompatApi23Impl(map: StreamConfigurationMap) :
+internal class StreamConfigurationMapCompatApi23Impl(map: StreamConfigurationMap?) :
     StreamConfigurationMapCompatBaseImpl(map) {
     override fun getOutputSizes(format: Int): Array<Size>? {
-        return streamConfigurationMap.getOutputSizes(format)
+        return streamConfigurationMap?.getOutputSizes(format)
     }
 
     override fun getHighResolutionOutputSizes(format: Int): Array<Size>? {
-        return streamConfigurationMap.getHighResolutionOutputSizes(format)
+        return streamConfigurationMap?.getHighResolutionOutputSizes(format)
     }
 }
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatBaseImpl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatBaseImpl.kt
index feeb433..b5bfa26 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatBaseImpl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/StreamConfigurationMapCompatBaseImpl.kt
@@ -24,7 +24,7 @@
 
 @RequiresApi(21)
 internal open class StreamConfigurationMapCompatBaseImpl(
-    val streamConfigurationMap: StreamConfigurationMap
+    val streamConfigurationMap: StreamConfigurationMap?
 ) :
     StreamConfigurationMapCompat.StreamConfigurationMapCompatImpl {
     override fun getOutputSizes(format: Int): Array<Size>? {
@@ -35,22 +35,22 @@
                 // after Android level 23 but not public in Android L. Use {@link SurfaceTexture}
                 // or {@link MediaCodec} will finally mapped to 0x22 in StreamConfigurationMap to
                 // retrieve the output sizes information.
-                streamConfigurationMap.getOutputSizes(SurfaceTexture::class.java)
+                streamConfigurationMap?.getOutputSizes(SurfaceTexture::class.java) ?: emptyArray()
             } else {
-                streamConfigurationMap.getOutputSizes(format)
+                streamConfigurationMap?.getOutputSizes(format) ?: emptyArray()
             }
         return sizes
     }
 
     override fun <T> getOutputSizes(klass: Class<T>): Array<Size>? {
-        return streamConfigurationMap.getOutputSizes(klass)
+        return streamConfigurationMap?.getOutputSizes(klass) ?: emptyArray()
     }
 
     override fun getHighResolutionOutputSizes(format: Int): Array<Size>? {
         return null
     }
 
-    override fun unwrap(): StreamConfigurationMap {
+    override fun unwrap(): StreamConfigurationMap? {
         return streamConfigurationMap
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AeFpsRangeLegacyQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AeFpsRangeLegacyQuirk.kt
new file mode 100644
index 0000000..e8c12f7
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AeFpsRangeLegacyQuirk.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.hardware.camera2.CameraCharacteristics
+import android.util.Range
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.core.impl.Quirk
+
+/**
+ *
+ * QuirkSummary
+ * - Bug Id: b/167425305
+ * - Description: Quirk required to maintain good exposure on legacy devices by specifying a
+ *                proper [android.hardware.camera2.CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE].
+ *                Legacy devices set the AE target FPS range to [30, 30]. This can potentially
+ *                cause underexposure issues.
+ *                [androidx.camera.camera2.internal.compat.workaround.AeFpsRange]
+ *                contains a workaround that is used on legacy devices to set a AE FPS range
+ *                whose upper bound is 30, which guarantees a smooth frame rate, and whose lower
+ *                bound is as small as possible to properly expose frames in low light
+ *                conditions. The default behavior on non legacy devices does not add the AE
+ *                FPS range option.
+ * - Device(s): All legacy devices
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class AeFpsRangeLegacyQuirk(cameraMetadata: CameraMetadata) : Quirk {
+    /**
+     * Returns the fps range whose upper is 30 and whose lower is the smallest, or null if no
+     * range has an upper equal to 30.  The rationale is:
+     * - Range upper is always 30 so that a smooth frame rate is guaranteed.
+     * - Range lower contains the smallest supported value so that it can adapt as much as
+     * possible to low light conditions.
+     */
+    val range: Range<Int>? by lazy {
+        val availableFpsRanges: Array<out Range<Int>>? =
+            cameraMetadata[CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES]
+        pickSuitableFpsRange(availableFpsRanges)
+    }
+
+    private fun pickSuitableFpsRange(
+        availableFpsRanges: Array<out Range<Int>>?
+    ): Range<Int>? {
+        if (availableFpsRanges.isNullOrEmpty()) {
+            return null
+        }
+        var pickedRange: Range<Int>? = null
+        for (fpsRangeBeforeCorrection in availableFpsRanges) {
+            val fpsRange = getCorrectedFpsRange(fpsRangeBeforeCorrection)
+            if (fpsRange.upper != 30) {
+                continue
+            }
+            if (pickedRange == null) {
+                pickedRange = fpsRange
+            } else {
+                if (fpsRange.lower < pickedRange.lower) {
+                    pickedRange = fpsRange
+                }
+            }
+        }
+        return pickedRange
+    }
+
+    /**
+     * On android 5.0/5.1, [CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES]
+     * returns wrong ranges whose values were multiplied by 1000. So we need to convert them to the
+     * correct values.
+     */
+    private fun getCorrectedFpsRange(fpsRange: Range<Int>): Range<Int> {
+        var newUpper = fpsRange.upper
+        var newLower = fpsRange.lower
+        if (fpsRange.upper >= 1000) {
+            newUpper = fpsRange.upper / 1000
+        }
+        if (fpsRange.lower >= 1000) {
+            newLower = fpsRange.lower / 1000
+        }
+        return Range(newLower, newUpper)
+    }
+
+    companion object {
+        fun isEnabled(cameraMetadata: CameraMetadata): Boolean {
+            val level = cameraMetadata[CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+            return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+        }
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AspectRatioLegacyApi21Quirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AspectRatioLegacyApi21Quirk.kt
index c46b711..3634002 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AspectRatioLegacyApi21Quirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/AspectRatioLegacyApi21Quirk.kt
@@ -47,7 +47,7 @@
     }
 
     companion object {
-        fun load(cameraMetadata: CameraMetadata): Boolean {
+        fun isEnabled(cameraMetadata: CameraMetadata): Boolean {
             val level: Int? = cameraMetadata[CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
             return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
                 Build.VERSION.SDK_INT == 21
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
index 522e38d..c46831d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
@@ -19,6 +19,7 @@
 import android.os.Build
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.core.impl.Quirk
@@ -29,7 +30,7 @@
 @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
 @CameraScope
 class CameraQuirks @Inject constructor(
-    private val cameraMetadata: CameraMetadata,
+    private val cameraMetadata: CameraMetadata?,
     private val streamConfigurationMapCompat: StreamConfigurationMapCompat
 ) {
 
@@ -39,13 +40,20 @@
      */
     val quirks: Quirks by lazy {
         val quirks: MutableList<Quirk> = mutableListOf()
+        if (cameraMetadata == null) {
+            Log.error { "Failed to enable quirks: camera metadata injection failed" }
+            return@lazy Quirks(quirks)
+        }
 
         // Go through all defined camera quirks in lexicographical order,
         // and add them to `quirks` if they should be loaded
+        if (AeFpsRangeLegacyQuirk.isEnabled(cameraMetadata)) {
+            quirks.add(AeFpsRangeLegacyQuirk(cameraMetadata))
+        }
         if (AfRegionFlipHorizontallyQuirk.isEnabled(cameraMetadata)) {
             quirks.add(AfRegionFlipHorizontallyQuirk())
         }
-        if (AspectRatioLegacyApi21Quirk.load(cameraMetadata)) {
+        if (AspectRatioLegacyApi21Quirk.isEnabled(cameraMetadata)) {
             quirks.add(AspectRatioLegacyApi21Quirk())
         }
         if (CamcorderProfileResolutionQuirk.isEnabled(cameraMetadata)) {
@@ -54,6 +62,9 @@
         if (CameraNoResponseWhenEnablingFlashQuirk.isEnabled(cameraMetadata)) {
             quirks.add(CameraNoResponseWhenEnablingFlashQuirk())
         }
+        if (ConfigureSurfaceToSecondarySessionFailQuirk.isEnabled(cameraMetadata)) {
+            quirks.add(ConfigureSurfaceToSecondarySessionFailQuirk())
+        }
         if (FlashTooSlowQuirk.isEnabled(cameraMetadata)) {
             quirks.add(FlashTooSlowQuirk())
         }
@@ -72,9 +83,18 @@
         if (JpegHalCorruptImageQuirk.isEnabled()) {
             quirks.add(JpegHalCorruptImageQuirk())
         }
+        if (PreviewOrientationIncorrectQuirk.isEnabled(cameraMetadata)) {
+            quirks.add(PreviewOrientationIncorrectQuirk())
+        }
+        if (TextureViewIsClosedQuirk.isEnabled(cameraMetadata)) {
+            quirks.add(TextureViewIsClosedQuirk())
+        }
         if (YuvImageOnePixelShiftQuirk.isEnabled()) {
             quirks.add(YuvImageOnePixelShiftQuirk())
         }
+        if (CaptureSessionStuckQuirk.isEnabled()) {
+            quirks.add(CaptureSessionStuckQuirk())
+        }
 
         Quirks(quirks)
     }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionOnClosedNotCalledQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionOnClosedNotCalledQuirk.kt
new file mode 100644
index 0000000..c97a228
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionOnClosedNotCalledQuirk.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import androidx.annotation.RequiresApi
+import androidx.camera.core.impl.Quirk
+
+/**
+ * A quirk to denote the devices may not receive
+ * [android.hardware.camera2.CameraCaptureSession.StateCallback.onClosed] callback.
+ *
+ * QuirkSummary
+ * - Bug Id:      144817309
+ * - Description: On Android API 22s and lower,
+ *                [android.hardware.camera2.CameraCaptureSession.StateCallback.onClosed] callback
+ *                will not be triggered under some circumstances.
+ * - Device(s):   Devices in Android API version <= 22
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class CaptureSessionOnClosedNotCalledQuirk : Quirk {
+    companion object {
+        /**
+         * The quirk is disabled for CameraPipe, as it intrinsically handles things without the
+         * reliance on the onClosed callback. For [androidx.camera.core.impl.DeferrableSurface] that
+         * does need this signal for ref-counting, CameraPipe has an extra pipeline that "finalizes"
+         * the capture session when a new capture session is created or the camera device is closed.
+         */
+        fun isEnabled(): Boolean = false
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionStuckQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionStuckQuirk.kt
new file mode 100644
index 0000000..9d3ba9e
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CaptureSessionStuckQuirk.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import androidx.annotation.RequiresApi
+import androidx.camera.core.impl.Quirk
+
+/**
+ * A quirk to denote the [android.hardware.camera2.CameraCaptureSession] cannot successfully be
+ * configured if the previous CameraCaptureSession doesn't finish its in-flight capture sequence.
+ *
+ * QuirkSummary
+ * - Bug Id:      146773463
+ * - Description: Opening and releasing the capture session quickly and constantly is a problem for
+ *                LEGACY devices. It needs to check that all the existing capture sessions have
+ *                finished the processing of their capture sequences before opening the next capture
+ *                session.
+ * - Device(s):   Devices in LEGACY camera hardware level.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class CaptureSessionStuckQuirk : Quirk {
+    companion object {
+        /**
+         * Always return false as CameraPipe handles this automatically. Please refer to
+         * [androidx.camera.camera2.pipe.compat.Camera2Quirks.shouldWaitForRepeatingRequest] for
+         * the conditions under which the quirk will be applied.
+         */
+        fun isEnabled(): Boolean = false
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ConfigureSurfaceToSecondarySessionFailQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ConfigureSurfaceToSecondarySessionFailQuirk.kt
new file mode 100644
index 0000000..98507ce
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ConfigureSurfaceToSecondarySessionFailQuirk.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.core.impl.Quirk
+import android.hardware.camera2.CameraCaptureSession
+
+/**
+ * A quirk to denote the surface can only be used to configure to only one
+ * [CameraCaptureSession], the next [CameraCaptureSession] may need to use
+ * another one.
+ *
+ * QuirkSummary
+ * - Bug Id: 129520942, 135050586
+ * - Description: Reusing a surface to create different [CameraCaptureSession] causes
+ *   crash on LEGACY devices.
+ * - Device(s): Devices in LEGACY camera hardware level.
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class ConfigureSurfaceToSecondarySessionFailQuirk : Quirk {
+
+    companion object {
+        fun isEnabled(cameraMetadata: CameraMetadata): Boolean {
+            val level = cameraMetadata[CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+            return level == INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+        }
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
index 1212eeb..0bbb1e9b 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/DeviceQuirksLoader.kt
@@ -52,19 +52,19 @@
         if (InvalidVideoProfilesQuirk.isEnabled()) {
             quirks.add(InvalidVideoProfilesQuirk())
         }
-        if (ExcludedSupportedSizesQuirk.load()) {
+        if (ExcludedSupportedSizesQuirk.isEnabled()) {
             quirks.add(ExcludedSupportedSizesQuirk())
         }
-        if (ExtraCroppingQuirk.load()) {
+        if (ExtraCroppingQuirk.isEnabled()) {
             quirks.add(ExtraCroppingQuirk())
         }
-        if (ExtraSupportedOutputSizeQuirk.load()) {
+        if (ExtraSupportedOutputSizeQuirk.isEnabled()) {
             quirks.add(ExtraSupportedOutputSizeQuirk())
         }
-        if (ExtraSupportedSurfaceCombinationsQuirk.load()) {
+        if (ExtraSupportedSurfaceCombinationsQuirk.isEnabled()) {
             quirks.add(ExtraSupportedSurfaceCombinationsQuirk())
         }
-        if (Nexus4AndroidLTargetAspectRatioQuirk.load()) {
+        if (Nexus4AndroidLTargetAspectRatioQuirk.isEnabled()) {
             quirks.add(Nexus4AndroidLTargetAspectRatioQuirk())
         }
         if (PreviewPixelHDRnetQuirk.isEnabled()) {
@@ -79,9 +79,12 @@
         if (TorchIsClosedAfterImageCapturingQuirk.isEnabled()) {
             quirks.add(TorchIsClosedAfterImageCapturingQuirk())
         }
-        if (SurfaceOrderQuirk.load()) {
+        if (SurfaceOrderQuirk.isEnabled()) {
             quirks.add(SurfaceOrderQuirk())
         }
+        if (CaptureSessionOnClosedNotCalledQuirk.isEnabled()) {
+            quirks.add(CaptureSessionOnClosedNotCalledQuirk())
+        }
         return quirks
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExcludedSupportedSizesQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExcludedSupportedSizesQuirk.kt
index c942233..4f6107d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExcludedSupportedSizesQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExcludedSupportedSizesQuirk.kt
@@ -41,7 +41,7 @@
  * J7 (SM-J710MN) API 27
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-class ExcludedSupportedSizesQuirk() : Quirk {
+class ExcludedSupportedSizesQuirk : Quirk {
     /**
      * Retrieves problematic supported surface sizes that have to be excluded on the current
      * device, for the given camera id and image format.
@@ -207,7 +207,7 @@
     companion object {
         private const val TAG: String = "ExcludedSupportedSizesQuirk"
         private const val UNKNOWN_IMAGE_FORMAT: Int = -1
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             return (isOnePlus6 || isOnePlus6T || isHuaweiP20Lite || isSamsungJ7PrimeApi27Above ||
                 isSamsungJ7Api27Above)
         }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirk.kt
index f391079..2e9b935 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirk.kt
@@ -75,7 +75,7 @@
                 "SM-G610M" to Range(21, 26)
             )
 
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             return isSamsungDistortion
         }
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedOutputSizeQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedOutputSizeQuirk.kt
index 971320f..fc4e622 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedOutputSizeQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedOutputSizeQuirk.kt
@@ -36,7 +36,7 @@
  */
 @SuppressLint("CameraXQuirksClassDetector")
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-class ExtraSupportedOutputSizeQuirk() : Quirk {
+class ExtraSupportedOutputSizeQuirk : Quirk {
     /**
      * Returns the extra supported resolutions on the device.
      */
@@ -76,7 +76,7 @@
         )
 
     companion object {
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             return isMotoE5Play
         }
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirk.kt
index 5a63102..83a2a88 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraSupportedSurfaceCombinationsQuirk.kt
@@ -242,7 +242,7 @@
                 "PIXEL 7 PRO"
             )
 
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             return (isSamsungS7 || supportExtraFullConfigurationsSamsungDevice() ||
                 supportExtraLevel3ConfigurationsGoogleDevice())
         }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.kt
index 7147ca8..9833eb1 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.kt
@@ -49,7 +49,7 @@
             "NEXUS 4" // b/158749159
         )
 
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             return "GOOGLE".equals(
                 Build.BRAND,
                 ignoreCase = true
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/PreviewOrientationIncorrectQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/PreviewOrientationIncorrectQuirk.kt
new file mode 100644
index 0000000..7428f9a
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/PreviewOrientationIncorrectQuirk.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.hardware.camera2.CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
+import android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.core.impl.Quirk
+
+/**
+ * A quirk where the orientation of the preview is incorrect while a surface to be used to
+ * configure on 2 different [android.hardware.camera2.CameraCaptureSession].
+ *
+ * QuirkSummary
+ * - Bug Id: 128577112
+ * - Description: Reusing a surface to create a different
+ *   [android.hardware.camera2.CameraCaptureSession] causes incorrect preview orientation for
+ *   LEGACY devices. Some GL related setting is left over when the legacy shim is recreated.
+ *   It causes the 2nd PreviewCaptureSession to be rotated and stretched compared to the 1st one.
+ * - Device(s): Devices in LEGACY camera hardware level.
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class PreviewOrientationIncorrectQuirk : Quirk {
+
+    companion object {
+        fun isEnabled(cameraMetadata: CameraMetadata): Boolean {
+            val level = cameraMetadata[INFO_SUPPORTED_HARDWARE_LEVEL]
+            return level == INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+        }
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/SurfaceOrderQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/SurfaceOrderQuirk.kt
index 19c893f..4778a85 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/SurfaceOrderQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/SurfaceOrderQuirk.kt
@@ -47,7 +47,7 @@
     companion object {
         private val BUILD_HARDWARE_SET = listOf("samsungexynos7570", "samsungexynos7870")
 
-        fun load(): Boolean {
+        fun isEnabled(): Boolean {
             // Apply this quirk to all devices to avoid that there are still some other devices with
             // the same quirk. The workaround is only to sort the input surface list when creating
             // CameraCaptureSession, so it does not cost much performance and should be safe to apply.
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/TextureViewIsClosedQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/TextureViewIsClosedQuirk.kt
new file mode 100644
index 0000000..136e3c6
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/TextureViewIsClosedQuirk.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.camera2.pipe.integration.compat.quirk
+
+import android.annotation.SuppressLint
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraMetadata
+import androidx.camera.core.impl.Quirk
+
+/**
+ * A quirk to denote a new surface should be acquired while the camera is going to create a new
+ * [android.hardware.camera2.CameraCaptureSession].
+ *
+ * QuirkSummary
+ * - Bug Id: 145725334
+ * - Description: When using TextureView below Android API 23, it releases
+ *   [android.graphics.SurfaceTexture] when activity is stopped.
+ * - Device(s): Devices in Android API version <= 23
+ *
+ * TODO(b/270421716): enable CameraXQuirksClassDetector lint check when kotlin is supported.
+ */
+@SuppressLint("CameraXQuirksClassDetector")
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class TextureViewIsClosedQuirk : Quirk {
+    companion object {
+        @Suppress("UNUSED_PARAMETER")
+        fun isEnabled(cameraMetadata: CameraMetadata): Boolean {
+            return Build.VERSION.SDK_INT <= Build.VERSION_CODES.M
+        }
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRange.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRange.kt
new file mode 100644
index 0000000..8f1c132
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRange.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat.workaround
+
+import android.util.Range
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.integration.compat.quirk.AeFpsRangeLegacyQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.config.CameraScope
+import javax.inject.Inject
+
+/**
+ * Sets an AE target FPS range on legacy devices from [AeFpsRangeLegacyQuirk] to maintain good
+ * exposure.
+ */
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+
+@CameraScope
+class AeFpsRange @Inject constructor(cameraQuirks: CameraQuirks) {
+    private val aeTargetFpsRange: Range<Int>? by lazy {
+        /** Chooses the AE target FPS range on legacy devices.  */
+        cameraQuirks.quirks[AeFpsRangeLegacyQuirk::class.java]?.range
+    }
+
+    /**
+     * Sets the [android.hardware.camera2.CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE]
+     * option on legacy device when possible.
+     */
+    fun getTargetAeFpsRange(): Range<Int>? {
+        return aeTargetFpsRange
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/InactiveSurfaceCloser.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/InactiveSurfaceCloser.kt
new file mode 100644
index 0000000..d08bbb9
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/InactiveSurfaceCloser.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+
+package androidx.camera.camera2.pipe.integration.compat.workaround
+
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.quirk.ConfigureSurfaceToSecondarySessionFailQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.PreviewOrientationIncorrectQuirk
+import androidx.camera.camera2.pipe.integration.compat.quirk.TextureViewIsClosedQuirk
+import androidx.camera.core.impl.DeferrableSurface
+import dagger.Module
+import dagger.Provides
+
+/**
+ * A workaround to close the DeferrableSurface if it has been configured to the camera.
+ *
+ * This workaround will be enabled when one of the [ConfigureSurfaceToSecondarySessionFailQuirk],
+ * [PreviewOrientationIncorrectQuirk], [TextureViewIsClosedQuirk] is loaded.
+ */
+interface InactiveSurfaceCloser {
+
+    fun configure(streamId: StreamId, deferrableSurface: DeferrableSurface, graph: CameraGraph)
+    fun onSurfaceInactive(deferrableSurface: DeferrableSurface)
+    fun closeAll()
+
+    @Module
+    abstract class Bindings {
+        companion object {
+            @Provides
+            fun provideInactiveSurfaceCloser(cameraQuirks: CameraQuirks): InactiveSurfaceCloser {
+                val enabled = cameraQuirks.quirks.run {
+                    contains(ConfigureSurfaceToSecondarySessionFailQuirk::class.java) ||
+                        contains(PreviewOrientationIncorrectQuirk::class.java) ||
+                        contains(TextureViewIsClosedQuirk::class.java)
+                }
+
+                return if (enabled) InactiveSurfaceCloserImpl() else NoOpInactiveSurfaceCloser
+            }
+        }
+    }
+}
+
+class InactiveSurfaceCloserImpl : InactiveSurfaceCloser {
+    private val lock = Any()
+    private val configuredOutputs = mutableListOf<ConfiguredOutput>()
+
+    override fun configure(
+        streamId: StreamId,
+        deferrableSurface: DeferrableSurface,
+        graph: CameraGraph
+    ) {
+        synchronized(lock) {
+            configuredOutputs.add(
+                ConfiguredOutput(
+                    streamId,
+                    deferrableSurface,
+                    graph
+                )
+            )
+        }
+    }
+
+    override fun onSurfaceInactive(deferrableSurface: DeferrableSurface) {
+        synchronized(lock) {
+            configuredOutputs.closeIfConfigured(deferrableSurface)
+        }
+    }
+
+    override fun closeAll() {
+        synchronized(lock) {
+            configuredOutputs.forEach { it.close() }
+            configuredOutputs.clear()
+        }
+    }
+
+    data class ConfiguredOutput(
+        val streamId: StreamId,
+        val deferrableSurface: DeferrableSurface,
+        val graph: CameraGraph
+    ) {
+        fun close() {
+            graph.setSurface(streamId, null)
+            deferrableSurface.close()
+        }
+
+        fun contains(deferrableSurface: DeferrableSurface): Boolean {
+            return this.deferrableSurface == deferrableSurface
+        }
+    }
+
+    private fun List<ConfiguredOutput>.closeIfConfigured(
+        deferrableSurface: DeferrableSurface
+    ) = forEach {
+        if (it.contains(deferrableSurface)) {
+            deferrableSurface.close()
+        }
+    }
+}
+
+object NoOpInactiveSurfaceCloser : InactiveSurfaceCloser {
+    override fun configure(
+        streamId: StreamId,
+        deferrableSurface: DeferrableSurface,
+        graph: CameraGraph
+    ) {
+        // Nothing to do.
+    }
+
+    override fun onSurfaceInactive(deferrableSurface: DeferrableSurface) {
+        // Nothing to do.
+    }
+
+    override fun closeAll() {
+        // Nothing to do.
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/OutputSizesCorrector.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/OutputSizesCorrector.kt
index 723c840..012e4ae 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/OutputSizesCorrector.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/workaround/OutputSizesCorrector.kt
@@ -26,6 +26,7 @@
 import androidx.camera.camera2.pipe.integration.compat.quirk.ExcludedSupportedSizesQuirk
 import androidx.camera.camera2.pipe.integration.compat.quirk.ExtraSupportedOutputSizeQuirk
 import androidx.camera.camera2.pipe.integration.config.CameraScope
+import androidx.camera.core.Logger
 import androidx.camera.core.impl.utils.AspectRatioUtil
 import androidx.camera.core.impl.utils.CompareSizesByArea
 import java.util.Collections
@@ -42,113 +43,152 @@
 @CameraScope
 @RequiresApi(21)
 class OutputSizesCorrector @Inject constructor(
-    private val cameraMetadata: CameraMetadata,
-    private val streamConfigurationMap: StreamConfigurationMap
+    private val cameraMetadata: CameraMetadata?,
+    private val streamConfigurationMap: StreamConfigurationMap?
 ) {
+    private val tag = "OutputSizesCorrector"
     private val excludedSupportedSizesQuirk: ExcludedSupportedSizesQuirk? =
         DeviceQuirks[ExcludedSupportedSizesQuirk::class.java]
     private val extraSupportedOutputSizeQuirk: ExtraSupportedOutputSizeQuirk? =
         DeviceQuirks[ExtraSupportedOutputSizeQuirk::class.java]
     private val targetAspectRatio: TargetAspectRatio = TargetAspectRatio()
+    private val streamConfigurationMapCompat =
+        StreamConfigurationMapCompat(streamConfigurationMap, this)
 
     /**
      * Applies the output sizes related quirks onto the input sizes array.
      */
-    fun applyQuirks(sizes: Array<Size>?, format: Int): Array<Size>? {
-        var result = addExtraSupportedOutputSizesByFormat(sizes, format)
-        result = excludeProblematicOutputSizesByFormat(result, format)
-        return excludeOutputSizesByTargetAspectRatioWorkaround(result)
+    fun applyQuirks(sizes: Array<Size>, format: Int): Array<Size> {
+        val sizeList = sizes.toMutableList()
+        addExtraSupportedOutputSizesByFormat(sizeList, format)
+        excludeProblematicOutputSizesByFormat(sizeList, format)
+        if (sizeList.isEmpty()) {
+            Logger.w(tag, "Sizes array becomes empty after excluding problematic output sizes.")
+        }
+        val resultSizeArray = excludeOutputSizesByTargetAspectRatioWorkaround(sizeList)
+        if (resultSizeArray.isEmpty()) {
+            Logger.w(tag, "Sizes array becomes empty after excluding output sizes by target" +
+                " aspect ratio workaround.")
+        }
+        return resultSizeArray
     }
 
     /**
      * Applies the output sizes related quirks onto the input sizes array.
      */
-    fun <T> applyQuirks(sizes: Array<Size>?, klass: Class<T>): Array<Size>? {
-        var result = addExtraSupportedOutputSizesByClass(sizes, klass)
-        result = excludeProblematicOutputSizesByClass(result, klass)
-        return excludeOutputSizesByTargetAspectRatioWorkaround(result)
+    fun <T> applyQuirks(sizes: Array<Size>, klass: Class<T>): Array<Size> {
+        val sizeList = sizes.toMutableList()
+        addExtraSupportedOutputSizesByClass(sizeList, klass)
+        excludeProblematicOutputSizesByClass(sizeList, klass)
+        if (sizeList.isEmpty()) {
+            Logger.w(tag, "Sizes array becomes empty after excluding problematic output sizes.")
+        }
+        val resultSizeArray = excludeOutputSizesByTargetAspectRatioWorkaround(sizeList)
+        if (resultSizeArray.isEmpty()) {
+            Logger.w(tag, "Sizes array becomes empty after excluding output sizes by target" +
+                " aspect ratio workaround.")
+        }
+        return resultSizeArray
     }
 
     /**
      * Adds extra supported output sizes for the specified format by ExtraSupportedOutputSizeQuirk.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param format the image format to apply the workaround
      */
     private fun addExtraSupportedOutputSizesByFormat(
-        sizes: Array<Size>?,
+        sizeList: MutableList<Size>,
         format: Int
-    ): Array<Size>? {
-        if (sizes == null || extraSupportedOutputSizeQuirk == null) {
-            return sizes
+    ) {
+        if (extraSupportedOutputSizeQuirk == null) {
+            return
         }
-        val extraSizes: Array<Size> =
-            extraSupportedOutputSizeQuirk.getExtraSupportedResolutions(format)
-        return concatNullableSizeLists(sizes.toList(), extraSizes.toList()).toTypedArray()
+        extraSupportedOutputSizeQuirk.getExtraSupportedResolutions(format).let {
+            if (it.isNotEmpty()) {
+                sizeList.addAll(it)
+            }
+        }
     }
 
     /**
      * Adds extra supported output sizes for the specified class by ExtraSupportedOutputSizeQuirk.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param klass the class to apply the workaround
      */
     private fun <T> addExtraSupportedOutputSizesByClass(
-        sizes: Array<Size>?,
+        sizeList: MutableList<Size>,
         klass: Class<T>
-    ): Array<Size>? {
-        if (sizes == null || extraSupportedOutputSizeQuirk == null) {
-            return sizes
+    ) {
+        if (extraSupportedOutputSizeQuirk == null) {
+            return
         }
-        val extraSizes: Array<Size> =
-            extraSupportedOutputSizeQuirk.getExtraSupportedResolutions(klass)
-        return concatNullableSizeLists(sizes.toList(), extraSizes.toList()).toTypedArray()
+        extraSupportedOutputSizeQuirk.getExtraSupportedResolutions(klass).let {
+            if (it.isNotEmpty()) {
+                sizeList.addAll(it)
+            }
+        }
     }
 
     /**
      * Excludes problematic output sizes for the specified format by
      * ExcludedSupportedSizesContainer.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param format the image format to apply the workaround
      */
     private fun excludeProblematicOutputSizesByFormat(
-        sizes: Array<Size>?,
+        sizeList: MutableList<Size>,
         format: Int
-    ): Array<Size>? {
-        if (sizes == null || excludedSupportedSizesQuirk == null) {
-            return sizes
+    ) {
+        if (cameraMetadata == null || excludedSupportedSizesQuirk == null) {
+            return
         }
-        val excludedSizes: List<Size> =
-            excludedSupportedSizesQuirk.getExcludedSizes(cameraMetadata.camera.value, format)
-
-        val resultList: MutableList<Size> = sizes.toMutableList()
-        resultList.removeAll(excludedSizes)
-        return resultList.toTypedArray()
+        excludedSupportedSizesQuirk.getExcludedSizes(cameraMetadata.camera.value, format).let {
+            if (it.isNotEmpty()) {
+                sizeList.removeAll(it)
+            }
+        }
     }
 
     /**
      * Excludes problematic output sizes for the specified class type by
      * ExcludedSupportedSizesContainer.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param klass the class to apply the workaround
      */
     private fun <T> excludeProblematicOutputSizesByClass(
-        sizes: Array<Size>?,
+        sizeList: MutableList<Size>,
         klass: Class<T>
-    ): Array<Size>? {
-        if (sizes == null || excludedSupportedSizesQuirk == null) {
-            return sizes
+    ) {
+        if (cameraMetadata == null || excludedSupportedSizesQuirk == null) {
+            return
         }
-        val excludedSizes: List<Size> =
-            excludedSupportedSizesQuirk.getExcludedSizes(cameraMetadata.camera.value, klass)
-
-        val resultList: MutableList<Size> = sizes.toMutableList()
-        resultList.removeAll(excludedSizes)
-        return resultList.toTypedArray()
+        excludedSupportedSizesQuirk.getExcludedSizes(cameraMetadata.camera.value, klass).let {
+            if (it.isNotEmpty()) {
+                sizeList.removeAll(it)
+            }
+        }
     }
 
     /**
      * Excludes output sizes by TargetAspectRatio.
+     *
+     * @param sizeList the original sizes list
      */
-    private fun excludeOutputSizesByTargetAspectRatioWorkaround(sizes: Array<Size>?): Array<Size>? {
-        if (sizes == null) {
-            return null
+    private fun excludeOutputSizesByTargetAspectRatioWorkaround(
+        sizeList: List<Size>
+    ): Array<Size> {
+        if (cameraMetadata == null) {
+            return sizeList.toTypedArray()
         }
 
         val targetAspectRatio: Int =
             targetAspectRatio[
                 cameraMetadata,
-                StreamConfigurationMapCompat(streamConfigurationMap, this)
+                streamConfigurationMapCompat
             ]
 
         var ratio: Rational? = null
@@ -161,7 +201,7 @@
                 AspectRatioUtil.ASPECT_RATIO_16_9
 
             TargetAspectRatio.RATIO_MAX_JPEG -> {
-                val maxJpegSize = Collections.max(sizes.asList(), CompareSizesByArea())
+                val maxJpegSize = Collections.max(sizeList, CompareSizesByArea())
                 ratio = Rational(maxJpegSize.width, maxJpegSize.height)
             }
 
@@ -170,30 +210,17 @@
         }
 
         if (ratio == null) {
-            return sizes
+            return sizeList.toTypedArray()
         }
 
-        val resultList: MutableList<Size> = java.util.ArrayList()
+        val resultList = mutableListOf<Size>()
 
-        for (size in sizes) {
+        for (size in sizeList) {
             if (AspectRatioUtil.hasMatchingAspectRatio(size, ratio)) {
                 resultList.add(size)
             }
         }
 
-        return if (resultList.isEmpty()) {
-            null
-        } else {
-            resultList.toTypedArray()
-        }
-    }
-
-    private fun concatNullableSizeLists(
-        sizeList1: List<Size>,
-        sizeList2: List<Size>
-    ): List<Size> {
-        val resultList: MutableList<Size> = ArrayList(sizeList1)
-        resultList.addAll(sizeList2)
-        return resultList
+        return resultList.toTypedArray()
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
index af4d4c0..b827dcd 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/CameraConfig.kt
@@ -20,11 +20,15 @@
 
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.params.StreamConfigurationMap
+import androidx.annotation.Nullable
 import androidx.annotation.RequiresApi
 import androidx.annotation.VisibleForTesting
+import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
 import androidx.camera.camera2.pipe.CameraPipe
+import androidx.camera.camera2.pipe.DoNotDisturbException
+import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.adapter.CameraControlAdapter
 import androidx.camera.camera2.pipe.integration.adapter.CameraInfoAdapter
 import androidx.camera.camera2.pipe.integration.adapter.CameraInternalAdapter
@@ -32,6 +36,8 @@
 import androidx.camera.camera2.pipe.integration.compat.CameraCompatModule
 import androidx.camera.camera2.pipe.integration.compat.EvCompCompat
 import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.quirk.CaptureSessionStuckQuirk
 import androidx.camera.camera2.pipe.integration.impl.CameraPipeCameraProperties
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.camera2.pipe.integration.impl.ComboRequestListener
@@ -118,9 +124,16 @@
         )
 
         @CameraScope
+        @Nullable
         @Provides
-        fun provideCameraMetadata(cameraPipe: CameraPipe, config: CameraConfig): CameraMetadata =
-            checkNotNull(cameraPipe.cameras().awaitCameraMetadata(config.cameraId))
+        fun provideCameraMetadata(cameraPipe: CameraPipe, config: CameraConfig): CameraMetadata? {
+            try {
+                return cameraPipe.cameras().awaitCameraMetadata(config.cameraId)
+            } catch (exception: DoNotDisturbException) {
+                Log.error { "Failed to inject camera metadata: Do Not Disturb mode is on." }
+            }
+            return null
+        }
 
         @CameraScope
         @Provides
@@ -128,10 +141,22 @@
         fun provideCameraIdString(config: CameraConfig): String = config.cameraId.value
 
         @CameraScope
+        @Nullable
         @Provides
-        fun provideStreamConfigurationMap(cameraMetadata: CameraMetadata): StreamConfigurationMap {
-            return cameraMetadata[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
-                ?: throw IllegalArgumentException("Cannot retrieve SCALER_STREAM_CONFIGURATION_MAP")
+        fun provideStreamConfigurationMap(
+            cameraMetadata: CameraMetadata?
+        ): StreamConfigurationMap? {
+            return cameraMetadata?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
+        }
+
+        @CameraScope
+        @Provides
+        fun provideCameraGraphFlags(cameraQuirks: CameraQuirks): CameraGraph.Flags {
+            if (cameraQuirks.quirks.contains(CaptureSessionStuckQuirk::class.java)) {
+                Log.debug { "CameraPipe should be enabling CaptureSessionStuckQuirk" }
+            }
+            // TODO(b/276354253): Set quirkWaitForRepeatingRequestOnDisconnect flag for overrides.
+            return CameraGraph.Flags()
         }
     }
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
index 9dd4b00..a4635da 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/config/UseCaseCameraConfig.kt
@@ -82,6 +82,7 @@
 class UseCaseCameraConfig(
     private val useCases: List<UseCase>,
     private val cameraStateAdapter: CameraStateAdapter,
+    private val cameraGraphFlags: CameraGraph.Flags,
 ) {
     @UseCaseCameraScope
     @Provides
@@ -142,6 +143,7 @@
                 camera = cameraConfig.cameraId,
                 streams = streamConfigMap.keys.toList(),
                 defaultListeners = listOf(callbackMap, requestListener),
+                flags = cameraGraphFlags,
             )
         )
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
index b402f17..f61c4bc 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
@@ -19,10 +19,12 @@
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraDevice
 import android.hardware.camera2.CaptureRequest
+import android.util.Range
 import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
 import androidx.camera.camera2.pipe.integration.adapter.propagateTo
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.AutoFlashAEModeDisabler
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.core.CameraControl
@@ -43,6 +45,7 @@
 class State3AControl @Inject constructor(
     val cameraProperties: CameraProperties,
     private val aeModeDisabler: AutoFlashAEModeDisabler,
+    private val aeFpsRange: AeFpsRange
 ) : UseCaseCameraControl, UseCaseCamera.RunningUseCasesChangeListener {
     private var _useCaseCamera: UseCaseCamera? = null
     override var useCaseCamera: UseCaseCamera?
@@ -94,10 +97,12 @@
     var template by updateOnPropertyChange(DEFAULT_REQUEST_TEMPLATE)
     var preferredAeMode: Int? by updateOnPropertyChange(null)
     var preferredFocusMode: Int? by updateOnPropertyChange(null)
+    var preferredAeFpsRange: Range<Int>? by updateOnPropertyChange(aeFpsRange.getTargetAeFpsRange())
 
     override fun reset() {
         synchronized(lock) { updateSignals.toList() }.cancelAll()
         preferredAeMode = null
+        preferredAeFpsRange = null
         preferredFocusMode = null
         flashMode = DEFAULT_FLASH_MODE
         template = DEFAULT_REQUEST_TEMPLATE
@@ -114,6 +119,8 @@
     }
 
     fun invalidate() {
+        // TODO(b/276779600): Refactor and move the setting of these parameter to
+        //  CameraGraph.Config(requiredParameters = mapOf(....)).
         val preferAeMode = preferredAeMode ?: when (flashMode) {
             ImageCapture.FLASH_MODE_OFF -> CaptureRequest.CONTROL_AE_MODE_ON
             ImageCapture.FLASH_MODE_ON -> CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH
@@ -125,14 +132,18 @@
 
         val preferAfMode = preferredFocusMode ?: getDefaultAfMode()
 
+        val parameters: MutableMap<CaptureRequest.Key<*>, Any> = mutableMapOf(
+            CaptureRequest.CONTROL_AE_MODE to getSupportedAeMode(preferAeMode),
+            CaptureRequest.CONTROL_AF_MODE to getSupportedAfMode(preferAfMode),
+            CaptureRequest.CONTROL_AWB_MODE to getSupportedAwbMode(
+                CaptureRequest.CONTROL_AWB_MODE_AUTO))
+
+        preferredAeFpsRange?.let {
+            parameters[CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE] = it
+        }
+
         useCaseCamera?.requestControl?.addParametersAsync(
-            values = mapOf(
-                CaptureRequest.CONTROL_AE_MODE to getSupportedAeMode(preferAeMode),
-                CaptureRequest.CONTROL_AF_MODE to getSupportedAfMode(preferAfMode),
-                CaptureRequest.CONTROL_AWB_MODE to getSupportedAwbMode(
-                    CaptureRequest.CONTROL_AWB_MODE_AUTO
-                ),
-            )
+            values = parameters
         )?.apply {
             toCompletableDeferred().also { signal ->
                 synchronized(lock) {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
index b1ebfec..a2457a4 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
@@ -36,6 +36,7 @@
 import javax.inject.Inject
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
@@ -134,7 +135,7 @@
 
     override fun close(): Job {
         return if (closed.compareAndSet(expect = false, update = true)) {
-            threads.scope.launch {
+            threads.scope.launch(start = CoroutineStart.UNDISPATCHED) {
                 debug { "Closing $this" }
                 useCaseGraphConfig.graph.close()
                 useCaseSurfaceManager.stopAsync().await()
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index b950079..222047d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -20,6 +20,7 @@
 import android.os.Build
 import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
 import androidx.camera.camera2.pipe.integration.config.CameraConfig
@@ -71,6 +72,7 @@
     private val controls: java.util.Set<UseCaseCameraControl>,
     private val camera2CameraControl: Camera2CameraControl,
     private val cameraStateAdapter: CameraStateAdapter,
+    private val cameraGraphFlags: CameraGraph.Flags,
     cameraProperties: CameraProperties,
     displayInfoManager: DisplayInfoManager,
 ) {
@@ -254,7 +256,9 @@
         }
 
         // Create and configure the new camera component.
-        _activeComponent = builder.config(UseCaseCameraConfig(useCases, cameraStateAdapter)).build()
+        _activeComponent =
+            builder.config(UseCaseCameraConfig(useCases, cameraStateAdapter, cameraGraphFlags))
+                .build()
         for (control in allControls) {
             control.useCaseCamera = camera
         }
@@ -277,6 +281,7 @@
 
         return !meteringRepeatingEnabled && (onlyVideoCapture || requireMeteringRepeating)
     }
+
     @GuardedBy("lock")
     private fun addRepeatingUseCase() {
         meteringRepeating.setupSession()
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManager.kt
index aaa34b8..94f1484 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManager.kt
@@ -27,6 +27,7 @@
 import androidx.camera.camera2.pipe.StreamId
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
+import androidx.camera.camera2.pipe.integration.compat.workaround.InactiveSurfaceCloser
 import androidx.camera.camera2.pipe.integration.config.UseCaseCameraScope
 import androidx.camera.core.impl.DeferrableSurface
 import androidx.camera.core.impl.DeferrableSurface.SurfaceClosedException
@@ -49,6 +50,7 @@
 class UseCaseSurfaceManager @Inject constructor(
     private val threads: UseCaseThreads,
     private val cameraPipe: CameraPipe,
+    private val inactiveSurfaceCloser: InactiveSurfaceCloser,
 ) : CameraSurfaceManager.SurfaceListener {
 
     private val lock = Any()
@@ -105,6 +107,7 @@
                         graph.setSurface(
                             stream = stream, surface = surface
                         )
+                        inactiveSurfaceCloser.configure(stream, it.key, graph)
                     }
                 } else {
                     // Only handle the first failed Surface since subsequent calls to
@@ -130,6 +133,7 @@
         setupSurfaceDeferred?.cancel()
 
         return synchronized(lock) {
+            inactiveSurfaceCloser.closeAll()
             configuredSurfaceMap = null
             stopDeferred = stopDeferred ?: CompletableDeferred<Unit>().apply {
                 invokeOnCompletion { synchronized(lock) { stopDeferred = null } }
@@ -161,6 +165,7 @@
         synchronized(lock) {
             activeSurfaceMap.remove(surface)?.let {
                 Log.debug { "SurfaceInactive $it in ${this@UseCaseSurfaceManager}" }
+                inactiveSurfaceCloser.onSurfaceInactive(it)
                 try {
                     it.decrementUseCount()
                 } catch (e: IllegalStateException) {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/CameraSelectionOptimizer.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/CameraSelectionOptimizer.kt
index a25e88c..35bc8dd 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/CameraSelectionOptimizer.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/internal/CameraSelectionOptimizer.kt
@@ -19,6 +19,7 @@
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraDevices
 import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.DoNotDisturbException
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.adapter.CameraFactoryAdapter
 import androidx.camera.camera2.pipe.integration.config.CameraAppComponent
@@ -100,27 +101,32 @@
             if (lensFacingInteger == null) { // Cannot skip any camera id.
                 return null
             }
-            if (lensFacingInteger.toInt() == CameraSelector.LENS_FACING_BACK) {
-                val camera0Metadata = cameraDevices.awaitCameraMetadata(CameraId("0"))
-                checkNotNull(camera0Metadata)
-                if (camera0Metadata[CameraCharacteristics.LENS_FACING]?.equals(
+            try {
+                if (lensFacingInteger.toInt() == CameraSelector.LENS_FACING_BACK) {
+                    val camera0Metadata = cameraDevices.awaitCameraMetadata(CameraId("0"))
+                    checkNotNull(camera0Metadata)
+                    if (camera0Metadata[CameraCharacteristics.LENS_FACING] ==
                         CameraCharacteristics.LENS_FACING_BACK
-                    )!!
-                ) {
-                    // If apps requires back lens facing,  and "0" is confirmed to be back
-                    // We can safely ignore "1" as a optimization for initialization latency
-                    skippedCameraId = "1"
-                }
-            } else if (lensFacingInteger.toInt() == CameraSelector.LENS_FACING_FRONT) {
-                val camera1Metadata = cameraDevices.awaitCameraMetadata(CameraId("1"))
-                checkNotNull(camera1Metadata)
-                if (camera1Metadata[CameraCharacteristics.LENS_FACING]?.equals(
+                    ) {
+                        // If apps requires back lens facing,  and "0" is confirmed to be back
+                        // We can safely ignore "1" as a optimization for initialization latency
+                        skippedCameraId = "1"
+                    }
+                } else if (lensFacingInteger.toInt() == CameraSelector.LENS_FACING_FRONT) {
+                    val camera1Metadata = cameraDevices.awaitCameraMetadata(CameraId("1"))
+                    checkNotNull(camera1Metadata)
+                    if (camera1Metadata[CameraCharacteristics.LENS_FACING] ==
                         CameraCharacteristics.LENS_FACING_FRONT
-                    )!!
-                ) {
-                    // If apps requires front lens facing,  and "1" is confirmed to be back
-                    // We can safely ignore "0" as a optimization for initialization latency
-                    skippedCameraId = "0"
+                    ) {
+                        // If apps requires front lens facing,  and "1" is confirmed to be back
+                        // We can safely ignore "0" as a optimization for initialization latency
+                        skippedCameraId = "0"
+                    }
+                }
+            } catch (exception: DoNotDisturbException) {
+                Log.error {
+                    "Received Do Not Disturb exception while deciding camera id to skip. " +
+                        "Please turn off Do Not Disturb mode"
                 }
             }
             return skippedCameraId
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index 3b0b4c2..b51e10f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -34,6 +34,7 @@
 import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
 import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
 import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.MeteringRegionCorrection
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpMeteringRegionCorrection
@@ -1584,6 +1585,18 @@
     ) = State3AControl(
         properties,
         NoOpAutoFlashAEModeDisabler,
+        AeFpsRange(
+            CameraQuirks(
+                FakeCameraMetadata(),
+                StreamConfigurationMapCompat(
+                    StreamConfigurationMapBuilder.newBuilder().build(),
+                    OutputSizesCorrector(
+                        FakeCameraMetadata(),
+                        StreamConfigurationMapBuilder.newBuilder().build()
+                    )
+                )
+            )
+        )
     ).apply {
         this.useCaseCamera = useCaseCamera
     }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
index 63199bb..a2eba78 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/OutputSizesCorrectorTest.kt
@@ -83,7 +83,7 @@
                 Size(3088, 3088),
             ),
             ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
-        )!!.toList()
+        ).toList()
 
         Truth.assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -120,7 +120,7 @@
                 Size(3088, 3088),
             ),
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         Truth.assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -152,7 +152,7 @@
         )
 
         val sizesWithQuirks: Array<Size> =
-            outputSizesCorrector.applyQuirks(outputSizes, ImageFormat.YUV_420_888)!!
+            outputSizesCorrector.applyQuirks(outputSizes, ImageFormat.YUV_420_888)
         val resultList = mutableListOf<Size>().apply {
             sizesWithQuirks.forEach { size ->
                 add(size)
@@ -192,7 +192,7 @@
         val resultList: List<Size> = outputSizesCorrector.applyQuirks(
             outputSizes,
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         Truth.assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -222,7 +222,7 @@
         val resultList = outputSizesCorrector.applyQuirks(
             outputSizes,
             ImageFormat.YUV_420_888
-        )!!.toList()
+        ).toList()
 
         val expectedList = if (Build.VERSION.SDK_INT == 21) {
             // non-4:3 sizes are removed
@@ -268,7 +268,7 @@
         val resultList = outputSizesCorrector.applyQuirks(
             outputSizes,
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         val expectedList = if (Build.VERSION.SDK_INT == 21) {
             // non-4:3 sizes are removed
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirkTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirkTest.kt
index 42b703a..9f7e6c3 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirkTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/quirk/ExtraCroppingQuirkTest.kt
@@ -36,14 +36,14 @@
     @Test
     fun deviceModelNotContained_returnsNull() {
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "non-existent")
-        assert(!ExtraCroppingQuirk.load())
+        assert(!ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.PRIV)).isNull()
     }
 
     @Test
     fun deviceBrandNotSamsung_returnsNull() {
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "non-existent")
-        assert(!ExtraCroppingQuirk.load())
+        assert(!ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.PRIV)).isNull()
     }
 
@@ -52,7 +52,7 @@
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "samsung")
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "SM-J710MN")
         ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 20)
-        assert(!ExtraCroppingQuirk.load())
+        assert(!ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.PRIV)).isNull()
     }
 
@@ -61,7 +61,7 @@
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "samsung")
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "SM-J710MN")
         ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 22)
-        assert(ExtraCroppingQuirk.load())
+        assert(ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.RAW)).isNull()
     }
 
@@ -70,7 +70,7 @@
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "samsung")
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "SM-J710MN")
         ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 22)
-        assert(ExtraCroppingQuirk.load())
+        assert(ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.PRIV))
             .isEqualTo(Size(1920, 1080))
     }
@@ -80,7 +80,7 @@
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "samsung")
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "SM-J710MN")
         ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 22)
-        assert(ExtraCroppingQuirk.load())
+        assert(ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.YUV))
             .isEqualTo(Size(1280, 720))
     }
@@ -90,7 +90,7 @@
         ReflectionHelpers.setStaticField(Build::class.java, "BRAND", "samsung")
         ReflectionHelpers.setStaticField(Build::class.java, "MODEL", "SM-J710MN")
         ReflectionHelpers.setStaticField(Build.VERSION::class.java, "SDK_INT", 22)
-        assert(ExtraCroppingQuirk.load())
+        assert(ExtraCroppingQuirk.isEnabled())
         Truth.assertThat(quirk.getVerifiedResolution(SurfaceConfig.ConfigType.JPEG))
             .isEqualTo(Size(3264, 1836))
     }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRangeTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRangeTest.kt
new file mode 100644
index 0000000..1f0626e
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/compat/workaround/AeFpsRangeTest.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.integration.compat.workaround
+
+import android.hardware.camera2.CameraCharacteristics
+import android.os.Build
+import android.util.Range
+import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.StreamConfigurationMapBuilder
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class AeFpsRangeTest {
+    @Test
+    fun validEntryExists_correctRangeIsSelected() {
+        val availableFpsRanges: Array<Range<Int>> = arrayOf(
+            Range(25, 30),
+            Range(7, 33),
+            Range(15, 30),
+            Range(11, 22),
+            Range(30, 30)
+        )
+        val aeFpsRange: AeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+                availableFpsRanges
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isEqualTo(Range(15, 30))
+    }
+
+    @Test
+    fun noValidEntry_doesNotSetFpsRange() {
+        val availableFpsRanges: Array<Range<Int>> = arrayOf(
+            Range(25, 25),
+            Range(7, 33),
+            Range(15, 24),
+            Range(11, 22)
+        )
+        val aeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+                availableFpsRanges
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isNull()
+    }
+
+    @Test
+    fun availableArrayIsNull_doesNotSetFpsRange() {
+        val aeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+                null
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isNull()
+    }
+
+    @Test
+    fun limitedDevices_doesNotSetFpsRange() {
+        val availableFpsRanges: Array<Range<Int>> = arrayOf(
+            Range(15, 30)
+        )
+        val aeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+                availableFpsRanges
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isNull()
+    }
+
+    @Test
+    fun fullDevices_doesNotSetFpsRange() {
+        val availableFpsRanges: Array<Range<Int>> = arrayOf(
+            Range(15, 30)
+        )
+        val aeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+                availableFpsRanges
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isNull()
+    }
+
+    @Test
+    fun level3Devices_doesNotSetFpsRange() {
+        val availableFpsRanges: Array<Range<Int>> = arrayOf(
+            Range(15, 30)
+        )
+        val aeFpsRange =
+            createAeFpsRange(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3,
+                availableFpsRanges
+            )
+        val pick = getAeFpsRange(aeFpsRange)
+        assertThat(pick).isNull()
+    }
+
+    private fun createAeFpsRange(
+        hardwareLevel: Int,
+        availableFpsRanges: Array<Range<Int>>?
+    ): AeFpsRange {
+        val streamConfigurationMap = StreamConfigurationMapBuilder.newBuilder().build()
+
+        val metadata = FakeCameraMetadata(
+            mapOf(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL to hardwareLevel,
+                CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES to availableFpsRanges,
+                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP to streamConfigurationMap
+            )
+        )
+        return AeFpsRange(
+            CameraQuirks(
+                metadata,
+                StreamConfigurationMapCompat(
+                    streamConfigurationMap,
+                    OutputSizesCorrector(metadata, streamConfigurationMap)
+                )
+            )
+        )
+    }
+
+    private fun getAeFpsRange(aeFpsRange: AeFpsRange): Range<Int>? {
+        return aeFpsRange.getTargetAeFpsRange()
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
index 34b3175..28e3c559 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
@@ -38,9 +38,13 @@
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
 import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
 import androidx.camera.camera2.pipe.integration.compat.workaround.CapturePipelineTorchCorrection
+import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
 import androidx.camera.camera2.pipe.integration.compat.workaround.NotUseTorchAsFlash
 import androidx.camera.camera2.pipe.integration.compat.workaround.UseTorchAsFlashImpl
+import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession
@@ -77,6 +81,7 @@
 import org.mockito.Mockito.mock
 import org.robolectric.annotation.Config
 import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.StreamConfigurationMapBuilder
 import org.robolectric.util.ReflectionHelpers
 
 @RunWith(RobolectricCameraPipeTestRunner::class)
@@ -207,6 +212,18 @@
             State3AControl(
                 fakeCameraProperties,
                 NoOpAutoFlashAEModeDisabler,
+                AeFpsRange(
+                    CameraQuirks(
+                        FakeCameraMetadata(),
+                        StreamConfigurationMapCompat(
+                            StreamConfigurationMapBuilder.newBuilder().build(),
+                            OutputSizesCorrector(
+                                FakeCameraMetadata(),
+                                StreamConfigurationMapBuilder.newBuilder().build()
+                            )
+                        )
+                    )
+                )
             ).apply {
                 useCaseCamera = fakeUseCaseCamera
             },
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
index 1666ff2..d281927 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
@@ -20,7 +20,11 @@
 import android.hardware.camera2.CaptureRequest
 import android.os.Build
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
+import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
+import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
@@ -43,6 +47,7 @@
 import org.junit.runner.RunWith
 import org.robolectric.annotation.Config
 import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.StreamConfigurationMapBuilder
 
 @RunWith(RobolectricCameraPipeTestRunner::class)
 @DoNotInstrument
@@ -71,8 +76,24 @@
     )
     private val fakeRequestControl = FakeUseCaseCameraRequestControl()
     private val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
+    private val aeFpsRange = AeFpsRange(
+        CameraQuirks(
+            FakeCameraMetadata(),
+            StreamConfigurationMapCompat(
+                StreamConfigurationMapBuilder.newBuilder().build(),
+                OutputSizesCorrector(
+                    FakeCameraMetadata(),
+                    StreamConfigurationMapBuilder.newBuilder().build()
+                )
+            )
+        )
+    )
     private val state3AControl =
-        State3AControl(FakeCameraProperties(metadata), NoOpAutoFlashAEModeDisabler).apply {
+        State3AControl(
+            FakeCameraProperties(metadata),
+            NoOpAutoFlashAEModeDisabler,
+            aeFpsRange
+            ).apply {
             useCaseCamera = fakeUseCaseCamera
         }
     private lateinit var flashControl: FlashControl
@@ -92,7 +113,11 @@
         val fakeCameraProperties = FakeCameraProperties()
 
         val flashControl = FlashControl(
-            State3AControl(fakeCameraProperties, NoOpAutoFlashAEModeDisabler).apply {
+            State3AControl(
+                fakeCameraProperties,
+                NoOpAutoFlashAEModeDisabler,
+                aeFpsRange
+            ).apply {
                 useCaseCamera = fakeUseCaseCamera
             },
             fakeUseCaseThreads,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
index aba1a20..e5d846e 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
@@ -20,7 +20,11 @@
 import android.os.Build
 import androidx.camera.camera2.pipe.Result3A
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
+import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
+import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
+import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
@@ -49,6 +53,7 @@
 import org.junit.runner.RunWith
 import org.robolectric.annotation.Config
 import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadows.StreamConfigurationMapBuilder
 
 @RunWith(RobolectricCameraPipeTestRunner::class)
 @DoNotInstrument
@@ -80,6 +85,18 @@
         // Set a CompletableDeferred without set it to completed.
         setTorchResult = CompletableDeferred()
     }
+    private val aeFpsRange = AeFpsRange(
+        CameraQuirks(
+            FakeCameraMetadata(),
+            StreamConfigurationMapCompat(
+                StreamConfigurationMapBuilder.newBuilder().build(),
+                OutputSizesCorrector(
+                    FakeCameraMetadata(),
+                    StreamConfigurationMapBuilder.newBuilder().build()
+                )
+            )
+        )
+    )
 
     private lateinit var torchControl: TorchControl
 
@@ -92,6 +109,7 @@
             State3AControl(
                 fakeCameraProperties,
                 NoOpAutoFlashAEModeDisabler,
+                aeFpsRange
             ).apply {
                 useCaseCamera = fakeUseCaseCamera
             },
@@ -109,7 +127,11 @@
             // Without a flash unit, this Job will complete immediately with a IllegalStateException
             TorchControl(
                 fakeCameraProperties,
-                State3AControl(fakeCameraProperties, NoOpAutoFlashAEModeDisabler).apply {
+                State3AControl(
+                    fakeCameraProperties,
+                    NoOpAutoFlashAEModeDisabler,
+                    aeFpsRange
+                ).apply {
                     useCaseCamera = fakeUseCaseCamera
                 },
                 fakeUseCaseThreads,
@@ -126,7 +148,11 @@
 
         val torchState = TorchControl(
             fakeCameraProperties,
-            State3AControl(fakeCameraProperties, NoOpAutoFlashAEModeDisabler).apply {
+            State3AControl(
+                fakeCameraProperties,
+                NoOpAutoFlashAEModeDisabler,
+                aeFpsRange
+            ).apply {
 
                 useCaseCamera = fakeUseCaseCamera
             },
@@ -146,7 +172,11 @@
 
             TorchControl(
                 fakeCameraProperties,
-                State3AControl(fakeCameraProperties, NoOpAutoFlashAEModeDisabler).apply {
+                State3AControl(
+                    fakeCameraProperties,
+                    NoOpAutoFlashAEModeDisabler,
+                    aeFpsRange
+                ).apply {
                     useCaseCamera = fakeUseCaseCamera
                 },
                 fakeUseCaseThreads,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
index c9621e7..cdf0307 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
@@ -23,6 +23,7 @@
 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
 import androidx.camera.camera2.pipe.integration.adapter.CaptureConfigAdapter
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
+import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpInactiveSurfaceCloser
 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
@@ -107,7 +108,8 @@
             useCases = arrayListOf(fakeUseCase),
             useCaseSurfaceManager = UseCaseSurfaceManager(
                 useCaseThreads,
-                CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext()))
+                CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext())),
+                NoOpInactiveSurfaceCloser,
             ),
             threads = useCaseThreads,
             requestControl = requestControl
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
index 008fea7..f0a9f17 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
@@ -18,6 +18,7 @@
 
 import android.os.Build
 import android.util.Size
+import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
@@ -274,6 +275,7 @@
             ComboRequestListener()
         ),
         cameraStateAdapter = CameraStateAdapter(),
+        cameraGraphFlags = CameraGraph.Flags(),
         displayInfoManager = DisplayInfoManager(ApplicationProvider.getApplicationContext()),
     ).also {
         useCaseManagerList.add(it)
@@ -282,7 +284,7 @@
     private fun createImageCapture(): ImageCapture =
         ImageCapture.Builder()
             .setCaptureOptionUnpacker { _, _ -> }
-            .setSessionOptionUnpacker() { _, _, _ -> }
+            .setSessionOptionUnpacker { _, _, _ -> }
             .build().also {
                 it.simulateActivation()
                 useCaseList.add(it)
@@ -291,7 +293,7 @@
     private fun createPreview(): Preview =
         Preview.Builder()
             .setCaptureOptionUnpacker { _, _ -> }
-            .setSessionOptionUnpacker() { _, _, _ -> }
+            .setSessionOptionUnpacker { _, _, _ -> }
             .build().apply {
                 setSurfaceProvider(
                     CameraXExecutors.mainThreadExecutor(),
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManagerTest.kt
index 0a0fbcf..0472eed 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseSurfaceManagerTest.kt
@@ -26,6 +26,7 @@
 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
 import androidx.camera.camera2.pipe.integration.adapter.TestDeferrableSurface
 import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
+import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpInactiveSurfaceCloser
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
 import androidx.camera.core.impl.DeferrableSurface
 import androidx.camera.core.impl.SessionConfig
@@ -114,6 +115,7 @@
         UseCaseSurfaceManager(
             useCaseThreads,
             CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext())),
+            NoOpInactiveSurfaceCloser,
         ).setupAsync(
             graph = fakeGraph,
             sessionConfigAdapter = SessionConfigAdapter(
@@ -166,6 +168,7 @@
         UseCaseSurfaceManager(
             useCaseThreads,
             CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext())),
+            NoOpInactiveSurfaceCloser,
         ).setupAsync(
             graph = fakeGraph,
             sessionConfigAdapter = SessionConfigAdapter(
@@ -224,6 +227,7 @@
         UseCaseSurfaceManager(
             useCaseThreads,
             CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext())),
+            NoOpInactiveSurfaceCloser,
         ).setupAsync(
             graph = fakeGraph,
             sessionConfigAdapter = SessionConfigAdapter(
@@ -284,6 +288,7 @@
         val useCaseSurfaceManager = UseCaseSurfaceManager(
             useCaseThreads,
             CameraPipe(CameraPipe.Config(ApplicationProvider.getApplicationContext())),
+            NoOpInactiveSurfaceCloser,
         )
         val deferred = useCaseSurfaceManager.setupAsync(
             graph = fakeGraph,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
index f0b520c..3e93b84 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
@@ -28,6 +28,7 @@
 import androidx.camera.camera2.pipe.integration.adapter.EncoderProfilesProviderAdapter
 import androidx.camera.camera2.pipe.integration.compat.StreamConfigurationMapCompat
 import androidx.camera.camera2.pipe.integration.compat.quirk.CameraQuirks
+import androidx.camera.camera2.pipe.integration.compat.workaround.AeFpsRange
 import androidx.camera.camera2.pipe.integration.compat.workaround.MeteringRegionCorrection
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
 import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
@@ -95,9 +96,6 @@
         zoomControl: ZoomControl = this.zoomControl,
     ): CameraInfoAdapter {
         val fakeUseCaseCamera = FakeUseCaseCamera()
-        val state3AControl = State3AControl(cameraProperties, NoOpAutoFlashAEModeDisabler).apply {
-            useCaseCamera = fakeUseCaseCamera
-        }
         val fakeStreamConfigurationMap = StreamConfigurationMapCompat(
             streamConfigurationMap,
             OutputSizesCorrector(cameraProperties.metadata, streamConfigurationMap)
@@ -106,6 +104,13 @@
             cameraProperties.metadata,
             fakeStreamConfigurationMap,
         )
+        val state3AControl = State3AControl(
+            cameraProperties,
+            NoOpAutoFlashAEModeDisabler,
+            AeFpsRange(fakeCameraQuirks)
+        ).apply {
+            useCaseCamera = fakeUseCaseCamera
+        }
         return CameraInfoAdapter(
             cameraProperties,
             CameraConfig(cameraId),
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index 64d3363..5c3279f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -40,7 +40,8 @@
 import kotlinx.coroutines.withTimeoutOrNull
 
 class FakeUseCaseCameraComponentBuilder : UseCaseCameraComponent.Builder {
-    private var config: UseCaseCameraConfig = UseCaseCameraConfig(emptyList(), CameraStateAdapter())
+    private var config: UseCaseCameraConfig =
+        UseCaseCameraConfig(emptyList(), CameraStateAdapter(), CameraGraph.Flags())
 
     override fun config(config: UseCaseCameraConfig): UseCaseCameraComponent.Builder {
         this.config = config
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
index b191c82..60e6949 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraError.kt
@@ -107,7 +107,7 @@
                 is IllegalArgumentException -> ERROR_ILLEGAL_ARGUMENT_EXCEPTION
                 is SecurityException -> ERROR_SECURITY_EXCEPTION
                 else -> {
-                    if (Build.VERSION.SDK_INT == 28 && isDoNotDisturbException(throwable)) {
+                    if (shouldHandleDoNotDisturbException(throwable)) {
                         ERROR_DO_NOT_DISTURB_ENABLED
                     } else {
                         throw IllegalArgumentException("Unexpected throwable: $throwable")
@@ -143,6 +143,9 @@
                 }
             }
 
+        internal fun shouldHandleDoNotDisturbException(throwable: Throwable): Boolean =
+            Build.VERSION.SDK_INT == 28 && isDoNotDisturbException(throwable)
+
         /**
          * The full stack trace of the Do Not Disturb exception on API level 28 is as follows:
          *
@@ -167,3 +170,6 @@
         }
     }
 }
+
+// TODO(b/276918807): When we have CameraProperties, handle the exception on a more granular level.
+class DoNotDisturbException(message: String) : RuntimeException(message)
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
index 37d48e4e..b1dda57 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
@@ -135,7 +135,22 @@
     data class Flags(
         val configureBlankSessionOnStop: Boolean = false,
         val abortCapturesOnStop: Boolean = false,
-        val allowMultipleActiveCameras: Boolean = false
+        val allowMultipleActiveCameras: Boolean = false,
+
+        /**
+         * A quirk that waits for the last repeating capture request to start before stopping the
+         * current capture session. Please refer to the bugs linked here, or
+         * [androidx.camera.camera2.pipe.compat.Camera2Quirks.shouldWaitForRepeatingRequest] for
+         * more information.
+         *
+         * This flag provides the overrides for you to override the default behavior (CameraPipe
+         * would turn on/off the quirk automatically based on device information).
+         *
+         * - Bug(s): b/146773463, b/267557892
+         * - Device(s): Camera devices on hardware level LEGACY
+         * - API levels: All
+         */
+        val quirkWaitForRepeatingRequestOnDisconnect: Boolean? = null,
     )
 
     enum class OperatingMode {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
index 0a4c5a5..e1772d1 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraController.kt
@@ -57,7 +57,7 @@
     private val captureSequenceProcessorFactory: Camera2CaptureSequenceProcessorFactory,
     private val virtualCameraManager: VirtualCameraManager,
     private val cameraSurfaceManager: CameraSurfaceManager,
-    private val timeSource: TimeSource
+    private val timeSource: TimeSource,
 ) : CameraController {
     override val cameraId: CameraId
         get() = config.camera
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
index e61a66e..318a90b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CameraMetadata.kt
@@ -125,7 +125,7 @@
         lazy(LazyThreadSafetyMode.PUBLICATION) {
             try {
                 Debug.trace("Camera-${camera.value}#keys") {
-                    @Suppress("UselessCallOnNotNull") characteristics.keys.orEmpty().toSet()
+                    characteristics.keys.orEmpty().toSet()
                 }
             } catch (e: AssertionError) {
                 Log.warn(e) {
@@ -139,7 +139,6 @@
         lazy(LazyThreadSafetyMode.PUBLICATION) {
             try {
                 Debug.trace("Camera-${camera.value}#availableCaptureRequestKeys") {
-                    @Suppress("UselessCallOnNotNull")
                     characteristics.availableCaptureRequestKeys.orEmpty().toSet()
                 }
             } catch (e: AssertionError) {
@@ -154,7 +153,6 @@
         lazy(LazyThreadSafetyMode.PUBLICATION) {
             try {
                 Debug.trace("Camera-${camera.value}#availableCaptureResultKeys") {
-                    @Suppress("UselessCallOnNotNull")
                     characteristics.availableCaptureResultKeys.orEmpty().toSet()
                 }
             } catch (e: AssertionError) {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
index 65a4eb3..c58f0f6 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequence.kt
@@ -33,6 +33,7 @@
 import androidx.camera.camera2.pipe.RequestMetadata
 import androidx.camera.camera2.pipe.RequestNumber
 import androidx.camera.camera2.pipe.StreamId
+import kotlinx.coroutines.CompletableDeferred
 
 /**
  * This class responds to events from a set of one or more requests. It uses the tag field on a
@@ -51,6 +52,7 @@
     private val surfaceMap: Map<Surface, StreamId>,
 ) : CameraCaptureSession.CaptureCallback(), CaptureSequence<CaptureRequest> {
     private val debugId = captureSequenceDebugIds.incrementAndGet()
+    private val hasStarted = CompletableDeferred<Unit>()
 
     @Volatile
     private var _sequenceNumber: Int? = null
@@ -92,6 +94,7 @@
         // normal circumstances this should never happen.
         val request = readRequestMetadata(requestNumber)
 
+        hasStarted.complete(Unit)
         invokeOnRequest(request) { it.onStarted(request, frameNumber, timestamp) }
     }
 
@@ -200,6 +203,7 @@
                 "$captureSequenceId!"
         }
 
+        hasStarted.complete(Unit)
         invokeOnRequests { request, _, listener -> listener.onRequestSequenceAborted(request) }
     }
 
@@ -212,5 +216,7 @@
         }
     }
 
+    internal suspend fun awaitStarted() = hasStarted.await()
+
     override fun toString(): String = "Camera2CaptureSequence-$debugId"
 }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
index 73418c4..9a9bd8ac 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2CaptureSequenceProcessor.kt
@@ -22,6 +22,7 @@
 import android.hardware.camera2.CaptureRequest
 import android.util.ArrayMap
 import android.view.Surface
+import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CaptureSequence
@@ -34,6 +35,7 @@
 import androidx.camera.camera2.pipe.RequestTemplate
 import androidx.camera.camera2.pipe.StreamGraph
 import androidx.camera.camera2.pipe.StreamId
+import androidx.camera.camera2.pipe.core.Debug
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.core.Threads
 import androidx.camera.camera2.pipe.graph.StreamGraphImpl
@@ -41,6 +43,7 @@
 import javax.inject.Inject
 import kotlin.reflect.KClass
 import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.runBlocking
 
 internal interface Camera2CaptureSequenceProcessorFactory {
     fun create(
@@ -54,7 +57,8 @@
 constructor(
     private val threads: Threads,
     private val graphConfig: CameraGraph.Config,
-    private val streamGraph: StreamGraphImpl
+    private val streamGraph: StreamGraphImpl,
+    private val quirks: Camera2Quirks,
 ) : Camera2CaptureSequenceProcessorFactory {
     @Suppress("UNCHECKED_CAST")
     override fun create(
@@ -63,7 +67,12 @@
     ): CaptureSequenceProcessor<*, CaptureSequence<Any>> {
         @Suppress("SyntheticAccessor")
         return Camera2CaptureSequenceProcessor(
-            session, threads, graphConfig.defaultTemplate, surfaceMap, streamGraph
+            session,
+            threads,
+            graphConfig.defaultTemplate,
+            surfaceMap,
+            streamGraph,
+            quirks.shouldWaitForRepeatingRequest(graphConfig)
         )
             as CaptureSequenceProcessor<Any, CaptureSequence<Any>>
     }
@@ -86,9 +95,18 @@
     private val threads: Threads,
     private val template: RequestTemplate,
     private val surfaceMap: Map<StreamId, Surface>,
-    private val streamGraph: StreamGraph
+    private val streamGraph: StreamGraph,
+    private val shouldWaitForRepeatingRequest: Boolean = false,
 ) : CaptureSequenceProcessor<CaptureRequest, Camera2CaptureSequence> {
     private val debugId = captureSequenceProcessorDebugIds.incrementAndGet()
+    private val lock = Any()
+
+    @GuardedBy("lock")
+    private var closed = false
+
+    @GuardedBy("lock")
+    private var lastSingleRepeatingRequestSequence: Camera2CaptureSequence? = null
+
     override fun build(
         isRepeating: Boolean,
         requests: List<Request>,
@@ -245,13 +263,20 @@
         )
     }
 
-    override fun submit(captureSequence: Camera2CaptureSequence): Int? {
+    override fun submit(captureSequence: Camera2CaptureSequence): Int? = synchronized(lock) {
+        if (closed) {
+            Log.warn { "Capture sequence processor closed. $captureSequence won't be submitted" }
+            return null
+        }
         val captureCallback = captureSequence as CameraCaptureSession.CaptureCallback
         // TODO: Update these calls to use executors on newer versions of the OS
         return if (captureSequence.captureRequestList.size == 1 &&
             session !is CameraConstrainedHighSpeedCaptureSessionWrapper
         ) {
             if (captureSequence.repeating) {
+                if (shouldWaitForRepeatingRequest) {
+                    lastSingleRepeatingRequestSequence = captureSequence
+                }
                 session.setRepeatingRequest(
                     captureSequence.captureRequestList[0], captureCallback, threads.camera2Handler
                 )
@@ -273,16 +298,27 @@
         }
     }
 
-    override fun abortCaptures() {
+    override fun abortCaptures(): Unit = synchronized(lock) {
+        if (closed) return
         session.abortCaptures()
     }
 
-    override fun stopRepeating() {
+    override fun stopRepeating(): Unit = synchronized(lock) {
+        if (closed) return
         session.stopRepeating()
     }
 
-    override fun close() {
+    override fun close() = synchronized(lock) {
         // Close should not shut down
+        Debug.trace("$this#close") {
+            if (shouldWaitForRepeatingRequest) {
+                lastSingleRepeatingRequestSequence?.let {
+                    Log.debug { "Waiting for the last repeating request sequence $it" }
+                    runBlocking { it.awaitStarted() }
+                }
+            }
+            closed = true
+        }
     }
 
     override fun toString(): String {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
new file mode 100644
index 0000000..95c0419
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2DeviceCloser.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.compat
+
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraDevice
+import android.view.Surface
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.core.Debug
+import androidx.camera.camera2.pipe.core.Log
+import androidx.camera.camera2.pipe.core.Threads
+import java.util.concurrent.CountDownLatch
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.atomicfu.atomic
+
+internal interface Camera2DeviceCloser {
+    fun closeCamera(
+        cameraDeviceWrapper: CameraDeviceWrapper? = null,
+        cameraDevice: CameraDevice? = null,
+        androidCameraState: AndroidCameraState,
+    )
+}
+
+@Singleton
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+internal class Camera2DeviceCloserImpl @Inject constructor(
+    val threads: Threads,
+    private val camera2Quirks: Camera2Quirks,
+) : Camera2DeviceCloser {
+    override fun closeCamera(
+        cameraDeviceWrapper: CameraDeviceWrapper?,
+        cameraDevice: CameraDevice?,
+        androidCameraState: AndroidCameraState,
+    ) {
+        val unwrappedCameraDevice = cameraDeviceWrapper?.unwrapAs(CameraDevice::class)
+        if (unwrappedCameraDevice != null) {
+            cameraDevice?.let {
+                check(unwrappedCameraDevice.id == it.id) {
+                    "Unwrapped camera device has camera ID ${unwrappedCameraDevice.id}, " + "" +
+                        "but the accompanied camera device has camera ID ${it.id}"
+                }
+            }
+            closeCameraDevice(unwrappedCameraDevice, androidCameraState)
+            cameraDeviceWrapper.onDeviceClosed()
+
+            // We only need to close the device once (don't want to create another capture session).
+            // Return here.
+            return
+        }
+        cameraDevice?.let { closeCameraDevice(it, androidCameraState) }
+    }
+
+    private fun closeCameraDevice(
+        cameraDevice: CameraDevice,
+        androidCameraState: AndroidCameraState,
+    ) {
+        val cameraId = CameraId.fromCamera2Id(cameraDevice.id)
+        if (camera2Quirks.shouldCreateCaptureSessionBeforeClosing(cameraId)) {
+            Debug.trace("Camera2DeviceCloserImpl#createCaptureSession") {
+                Log.debug { "Creating an empty capture session before closing camera $cameraId" }
+                createCaptureSession(cameraDevice)
+                Log.debug { "Empty capture session quirk completed" }
+            }
+        }
+        Log.debug { "Closing $cameraDevice" }
+        cameraDevice.closeWithTrace()
+        if (camera2Quirks.shouldWaitForCameraDeviceOnClosed(cameraId)) {
+            Log.debug { "Waiting for camera device to be completely closed" }
+            if (androidCameraState.awaitCameraDeviceClosed(timeoutMillis = 2000)) {
+                Log.debug { "Camera device is closed" }
+            } else {
+                Log.warn { "Failed to wait for camera device to close after 1500ms" }
+            }
+        }
+    }
+
+    private fun createCaptureSession(cameraDevice: CameraDevice) {
+        val surfaceTexture = SurfaceTexture(0).also { it.setDefaultBufferSize(640, 480) }
+        val surface = Surface(surfaceTexture)
+        val surfaceReleased = atomic(false)
+        val sessionConfigured = CountDownLatch(1)
+        val callback = object : CameraCaptureSession.StateCallback() {
+            override fun onConfigured(session: CameraCaptureSession) {
+                Log.debug { "Empty capture session configured. Closing it" }
+                // We don't need to wait for the session to close, instead we can just invoke
+                // close() and end here.
+                session.close()
+                sessionConfigured.countDown()
+            }
+
+            override fun onClosed(session: CameraCaptureSession) {
+                Log.debug { "Empty capture session closed" }
+                if (surfaceReleased.compareAndSet(expect = false, update = true)) {
+                    surface.release()
+                    surfaceTexture.release()
+                }
+            }
+
+            override fun onConfigureFailed(session: CameraCaptureSession) {
+                Log.debug { "Empty capture session configure failed" }
+                if (surfaceReleased.compareAndSet(expect = false, update = true)) {
+                    surface.release()
+                    surfaceTexture.release()
+                }
+                sessionConfigured.countDown()
+            }
+        }
+        try {
+            // This function was deprecated in Android Q, but is required since this quirk is
+            // needed on older API levels.
+            @Suppress("deprecation")
+            cameraDevice.createCaptureSession(listOf(surface), callback, threads.camera2Handler)
+        } catch (throwable: Throwable) {
+            Log.error(throwable) {
+                "Failed to create a blank capture session. " +
+                    "Surfaces may not be disconnected properly"
+            }
+            if (surfaceReleased.compareAndSet(expect = false, update = true)) {
+                surface.release()
+                surfaceTexture.release()
+            }
+        }
+        sessionConfigured.await()
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
index 73a1a99..28b0805 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2MetadataCache.kt
@@ -21,9 +21,11 @@
 import android.util.ArrayMap
 import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraError
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
 import androidx.camera.camera2.pipe.CameraPipe
+import androidx.camera.camera2.pipe.DoNotDisturbException
 import androidx.camera.camera2.pipe.config.CameraPipeContext
 import androidx.camera.camera2.pipe.core.Debug
 import androidx.camera.camera2.pipe.core.Log
@@ -127,8 +129,13 @@
                 }
 
                 return@trace cameraMetadata
-            } catch (e: Throwable) {
-                throw IllegalStateException("Failed to load metadata for $cameraId!", e)
+            } catch (throwable: Throwable) {
+                if (CameraError.shouldHandleDoNotDisturbException(throwable)) {
+                    throw DoNotDisturbException(
+                        "Failed to load metadata: Do Not Disturb mode is on!"
+                    )
+                }
+                throw IllegalStateException("Failed to load metadata for $cameraId!", throwable)
             }
         }
     }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Quirks.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Quirks.kt
new file mode 100644
index 0000000..a56125a
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Camera2Quirks.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.compat
+
+import android.hardware.camera2.CameraCharacteristics
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.CameraId
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+internal class Camera2Quirks @Inject constructor(
+    private val metadataProvider: Camera2MetadataProvider,
+) {
+    /**
+     * A quirk that waits for the last repeating capture request to start before stopping the
+     * current capture session. This is an issue in the Android camera framework where recreating
+     * a capture session too quickly can cause it to deadlock itself (stuck in its idle state),
+     * preventing us from successfully recreating a capture session.
+     *
+     * - Bug(s): b/146773463, b/267557892
+     * - Device(s): Camera devices on hardware level LEGACY
+     * - API levels: All
+     */
+    internal fun shouldWaitForRepeatingRequest(graphConfig: CameraGraph.Config): Boolean {
+        // First, check for overrides.
+        graphConfig.flags.quirkWaitForRepeatingRequestOnDisconnect?.let { return it }
+
+        // Then we verify whether we need this quirk based on hardware level.
+        val level = metadataProvider.awaitCameraMetadata(graphConfig.camera)[
+            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+        return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+    }
+
+    /**
+     * A quirk that creates a blank capture session before closing the camera. This is an issue in
+     * the Android camera framework where it doesn't disconnect the current Surfaces when the camera
+     * device is closed. For this reason, we create a blank capture session, and during which, the
+     * camera framework would disconnect the Surfaces. Another key thing to note is we also need to
+     * wait for the capture session to be configured, since the Surface disconnect calls are done
+     * almost at the very end of session configuration.
+     *
+     * - Bug(s): b/128600230, b/267559562
+     * - Device(s): Camera devices on hardware level LEGACY
+     * - API levels: 24 (N) – 28 (P)
+     */
+    internal fun shouldCreateCaptureSessionBeforeClosing(cameraId: CameraId): Boolean {
+        if (Build.VERSION.SDK_INT !in (Build.VERSION_CODES.N..Build.VERSION_CODES.P)) {
+            return false
+        }
+        val level = metadataProvider.awaitCameraMetadata(cameraId)[
+            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+        return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+    }
+
+    /**
+     * A quirk that waits for [android.hardware.camera2.CameraDevice.StateCallback.onClosed] to
+     * come back before finalizing the current session during camera close. This is needed because
+     * on legacy camera devices, releasing a Surface while camera frames are still being produced
+     * would trigger crashes.
+     *
+     * - Bug(s): b/130759707
+     * - Device(s): Camera devices on hardware level LEGACY
+     * - API levels: All
+     */
+    internal fun shouldWaitForCameraDeviceOnClosed(cameraId: CameraId): Boolean {
+        val level = metadataProvider.awaitCameraMetadata(cameraId)[
+            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+        return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
index 27722eb..7e50da5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CameraDeviceWrapper.kt
@@ -27,6 +27,7 @@
 import android.os.Build
 import android.os.Handler
 import android.view.Surface
+import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraMetadata
@@ -108,13 +109,6 @@
     fun onDeviceClosed()
 }
 
-internal fun CameraDeviceWrapper?.closeWithTrace() {
-    this?.let {
-        it.unwrapAs(CameraDevice::class).closeWithTrace()
-        it.onDeviceClosed()
-    }
-}
-
 internal fun CameraDevice?.closeWithTrace() {
     val timeSource = SystemTimeSource()
     this?.let {
@@ -340,3 +334,154 @@
             else -> null
         }
 }
+
+/**
+ * VirtualAndroidCameraDevice creates a simple wrapper around a [AndroidCameraDevice], augmenting
+ * it by enabling it to reject further capture session/request calls when it is "disconnected'.
+ */
+internal class VirtualAndroidCameraDevice(
+    internal val androidCameraDevice: AndroidCameraDevice,
+) : CameraDeviceWrapper {
+    private val lock = Any()
+
+    @GuardedBy("lock")
+    private var disconnected = false
+
+    override val cameraId: CameraId
+        get() = androidCameraDevice.cameraId
+
+    override fun createCaptureSession(
+        outputs: List<Surface>,
+        stateCallback: CameraCaptureSessionWrapper.StateCallback,
+        handler: Handler?
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn { "createCaptureSession failed: Virtual device disconnected" }
+            false
+        } else {
+            androidCameraDevice.createCaptureSession(outputs, stateCallback, handler)
+        }
+    }
+
+    @RequiresApi(23)
+    override fun createReprocessableCaptureSession(
+        input: InputConfiguration,
+        outputs: List<Surface>,
+        stateCallback: CameraCaptureSessionWrapper.StateCallback,
+        handler: Handler?
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn { "createReprocessableCaptureSession failed: Virtual device disconnected" }
+            false
+        } else {
+            androidCameraDevice.createReprocessableCaptureSession(
+                input,
+                outputs,
+                stateCallback,
+                handler
+            )
+        }
+    }
+
+    @RequiresApi(23)
+    override fun createConstrainedHighSpeedCaptureSession(
+        outputs: List<Surface>,
+        stateCallback: CameraCaptureSessionWrapper.StateCallback,
+        handler: Handler?
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn {
+                "createConstrainedHighSpeedCaptureSession failed: Virtual device disconnected"
+            }
+            false
+        } else {
+            androidCameraDevice.createConstrainedHighSpeedCaptureSession(
+                outputs,
+                stateCallback,
+                handler
+            )
+        }
+    }
+
+    @RequiresApi(24)
+    override fun createCaptureSessionByOutputConfigurations(
+        outputConfigurations: List<OutputConfigurationWrapper>,
+        stateCallback: CameraCaptureSessionWrapper.StateCallback,
+        handler: Handler?
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn {
+                "createCaptureSessionByOutputConfigurations failed: Virtual device disconnected"
+            }
+            false
+        } else {
+            androidCameraDevice.createCaptureSessionByOutputConfigurations(
+                outputConfigurations,
+                stateCallback,
+                handler
+            )
+        }
+    }
+
+    @RequiresApi(24)
+    override fun createReprocessableCaptureSessionByConfigurations(
+        inputConfig: InputConfigData,
+        outputs: List<OutputConfigurationWrapper>,
+        stateCallback: CameraCaptureSessionWrapper.StateCallback,
+        handler: Handler?
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn {
+                "createReprocessableCaptureSessionByConfigurations failed: " +
+                    "Virtual device disconnected"
+            }
+            false
+        } else {
+            androidCameraDevice.createReprocessableCaptureSessionByConfigurations(
+                inputConfig,
+                outputs,
+                stateCallback,
+                handler
+            )
+        }
+    }
+
+    @RequiresApi(28)
+    override fun createCaptureSession(config: SessionConfigData) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn { "createCaptureSession failed: Virtual device disconnected" }
+            false
+        } else {
+            androidCameraDevice.createCaptureSession(config)
+        }
+    }
+
+    override fun createCaptureRequest(template: RequestTemplate) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn { "createCaptureRequest failed: Virtual device disconnected" }
+            null
+        } else {
+            androidCameraDevice.createCaptureRequest(template)
+        }
+    }
+
+    @RequiresApi(23)
+    override fun createReprocessCaptureRequest(
+        inputResult: TotalCaptureResult
+    ) = synchronized(lock) {
+        if (disconnected) {
+            Log.warn { "createReprocessCaptureRequest failed: Virtual device disconnected" }
+            null
+        } else {
+            androidCameraDevice.createReprocessCaptureRequest(inputResult)
+        }
+    }
+
+    override fun onDeviceClosed() = androidCameraDevice.onDeviceClosed()
+
+    override fun <T : Any> unwrapAs(type: KClass<T>): T? = androidCameraDevice.unwrapAs(type)
+
+    internal fun disconnect() = synchronized(lock) {
+        disconnected = true
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
index 2ca96faf..aaac679 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionState.kt
@@ -241,7 +241,7 @@
      * a closed state. This will not cancel repeating requests or abort captures.
      */
     fun disconnect() {
-        shutdown(false)
+        shutdown(abortAndStopRepeating = false)
     }
 
     /**
@@ -263,21 +263,6 @@
 
         val graphProcessor = configuredCaptureSession?.processor
         if (graphProcessor != null) {
-            Log.debug { "$this Shutdown" }
-
-            Debug.traceStart { "$this#shutdown" }
-            Debug.traceStart { "$graphListener#onGraphStopped" }
-            graphListener.onGraphStopped(graphProcessor)
-            Debug.traceStop()
-            if (abortAndStopRepeating) {
-                Debug.traceStart { "$this#stopRepeating" }
-                graphProcessor.stopRepeating()
-                Debug.traceStop()
-                Debug.traceStart { "$this#stopRepeating" }
-                graphProcessor.abortCaptures()
-                Debug.traceStop()
-            }
-
             // WARNING:
             // This does NOT call close on the captureSession to avoid potentially slow
             // reconfiguration during mode switch and shutdown. This avoids unintentional restarts
@@ -288,6 +273,20 @@
             // cleanly unless the device is also closed. See b/135125484 for example.
             //
             // WARNING - DO NOT CALL session.close().
+            Log.debug { "$this Shutdown" }
+
+            Debug.traceStart { "$this#shutdown" }
+            Debug.traceStart { "$graphListener#onGraphStopped" }
+            graphListener.onGraphStopped(graphProcessor)
+            Debug.traceStop()
+            if (abortAndStopRepeating) {
+                Debug.traceStart { "$this#stopRepeating" }
+                graphProcessor.stopRepeating()
+                Debug.traceStop()
+                Debug.traceStart { "$this#abortCaptures" }
+                graphProcessor.abortCaptures()
+                Debug.traceStop()
+            }
 
             Debug.traceStop()
         }
@@ -297,7 +296,7 @@
             // If the CameraDevice is never opened, the session will never be created. For cleanup
             // reasons, make sure the session is finalized after shutdown if the cameraDevice was
             // never set.
-            shouldFinalizeSession = _cameraDevice == null
+            shouldFinalizeSession = _cameraDevice == null && state != State.CLOSED
             _cameraDevice = null
             state = State.CLOSED
         }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpener.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpener.kt
index 6f19a06..e5929d6 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpener.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpener.kt
@@ -151,6 +151,7 @@
     private val cameraOpener: CameraOpener,
     private val camera2MetadataProvider: Camera2MetadataProvider,
     private val cameraErrorListener: CameraErrorListener,
+    private val camera2DeviceCloser: Camera2DeviceCloser,
     private val timeSource: TimeSource,
     private val cameraInteropConfig: CameraPipe.CameraInteropConfig?
 ) {
@@ -168,6 +169,7 @@
                 requestTimestamp,
                 timeSource,
                 cameraErrorListener,
+                camera2DeviceCloser,
                 cameraInteropConfig?.cameraDeviceStateCallback,
                 cameraInteropConfig?.cameraSessionStateCallback
             )
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
index 04cfadb..45f13c5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCamera.kt
@@ -37,6 +37,8 @@
 import androidx.camera.camera2.pipe.core.Token
 import androidx.camera.camera2.pipe.graph.GraphListener
 import androidx.camera.camera2.pipe.internal.CameraErrorListener
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlin.coroutines.EmptyCoroutineContext
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.Job
@@ -125,6 +127,9 @@
     @GuardedBy("lock")
     private var closed = false
 
+    @GuardedBy("lock")
+    private var currentVirtualAndroidCamera: VirtualAndroidCameraDevice? = null
+
     // This is intended so that it will only ever replay the most recent event to new subscribers,
     // but to never drop events for existing subscribers.
     private val _stateFlow = MutableSharedFlow<CameraState>(replay = 1, extraBufferCapacity = 3)
@@ -132,6 +137,7 @@
 
     @GuardedBy("lock")
     private var _lastState: CameraState = CameraStateUnopened
+
     override val state: Flow<CameraState>
         get() = _states
 
@@ -153,12 +159,40 @@
                 return@coroutineScope
             }
 
+            // Here we generally relay what we receive from AndroidCameraState's state flow, except
+            // for CameraStateOpen. When the AndroidCameraDevice is provided through
+            // CameraStateOpen, we create a wrapper (VirtualAndroidCameraDevice) around it,
+            // allowing the AndroidCameraDevice to be "disconnected". This prevents additional calls
+            // such as createCaptureSession() from being executed on the camera device.
+            //
+            // Why it's needed: When 2 CameraGraphs are created and started in quick succession, say
+            // we have CameraGraph-1 and CameraGraph-2, it is possible for CameraGraph-2 to create
+            // its capture session _earlier_ than CameraGraph-1, as they run on separate threads.
+            // Because the two createCaptureSession() calls happen out of order, the more recent
+            // call wins, causing the session for CameraGraph-1 to succeed (even when it's already
+            // closed) and the session for CameraGraph-2 to fail (even though it was started most
+            // recently).
+            //
+            // Relevant bug: b/269619541
             job =
                 launch(EmptyCoroutineContext) {
                     state.collect {
                         synchronized(lock) {
                             if (!closed) {
-                                emitState(it)
+                                if (it is CameraStateOpen) {
+                                    val virtualAndroidCamera = VirtualAndroidCameraDevice(
+                                        it.cameraDevice as AndroidCameraDevice
+                                    )
+                                    // The ordering here is important. We need to set the current
+                                    // VirtualAndroidCameraDevice before emitting it out. Otherwise,
+                                    // the capture session can be started while we still don't have
+                                    // the current VirtualAndroidCameraDevice to disconnect when
+                                    // VirtualCameraState.disconnect() is called in parallel.
+                                    currentVirtualAndroidCamera = virtualAndroidCamera
+                                    emitState(CameraStateOpen(virtualAndroidCamera))
+                                } else {
+                                    emitState(it)
+                                }
                             }
                         }
                     }
@@ -176,6 +210,7 @@
 
             Log.info { "Disconnecting $this" }
 
+            currentVirtualAndroidCamera?.disconnect()
             job?.cancel()
             wakelockToken?.release()
 
@@ -214,6 +249,7 @@
     private val attemptTimestampNanos: TimestampNs,
     private val timeSource: TimeSource,
     private val cameraErrorListener: CameraErrorListener,
+    private val camera2DeviceCloser: Camera2DeviceCloser,
     private val interopDeviceStateCallback: CameraDevice.StateCallback? = null,
     private val interopSessionStateCallback: CameraCaptureSession.StateCallback? = null
 ) : CameraDevice.StateCallback() {
@@ -226,6 +262,8 @@
     @GuardedBy("lock")
     private var pendingClose: ClosingInfo? = null
 
+    private val cameraDeviceClosed = CountDownLatch(1)
+
     private val requestTimestampNanos: TimestampNs
     private var openTimestampNanos: TimestampNs? = null
 
@@ -262,6 +300,9 @@
         state.first { it is CameraStateClosed }
     }
 
+    internal fun awaitCameraDeviceClosed(timeoutMillis: Long): Boolean =
+        cameraDeviceClosed.await(timeoutMillis, TimeUnit.MILLISECONDS)
+
     override fun onOpened(cameraDevice: CameraDevice) {
         check(cameraDevice.id == cameraId.value)
         val openedTimestamp = Timestamps.now(timeSource)
@@ -291,7 +332,7 @@
         }
         interopDeviceStateCallback?.onOpened(cameraDevice)
         if (closeCamera) {
-            cameraDevice.close()
+            camera2DeviceCloser.closeCamera(cameraDevice = cameraDevice, androidCameraState = this)
             return
         }
 
@@ -316,7 +357,7 @@
             }
         if (closeInfo != null) {
             _state.value = CameraStateClosing(closeInfo.errorCode)
-            cameraDevice.closeWithTrace()
+            camera2DeviceCloser.closeCamera(cameraDevice = cameraDevice, androidCameraState = this)
             _state.value = computeClosedState(closeInfo)
         }
         Debug.traceStop()
@@ -326,6 +367,7 @@
         check(cameraDevice.id == cameraId.value)
         Debug.traceStart { "Camera-${cameraId.value}#onDisconnected" }
         Log.debug { "$cameraId: onDisconnected" }
+        cameraDeviceClosed.countDown()
 
         closeWith(
             cameraDevice,
@@ -343,6 +385,7 @@
         check(cameraDevice.id == cameraId.value)
         Debug.traceStart { "Camera-${cameraId.value}#onError-$errorCode" }
         Log.debug { "$cameraId: onError $errorCode" }
+        cameraDeviceClosed.countDown()
 
         closeWith(
             cameraDevice,
@@ -357,6 +400,7 @@
         check(cameraDevice.id == cameraId.value)
         Debug.traceStart { "Camera-${cameraId.value}#onClosed" }
         Log.debug { "$cameraId: onClosed" }
+        cameraDeviceClosed.countDown()
 
         closeWith(
             cameraDevice, @Suppress("SyntheticAccessor") ClosingInfo(ClosedReason.CAMERA2_CLOSED)
@@ -416,8 +460,11 @@
             }
             _state.value = CameraStateClosing(closeInfo.errorCode)
 
-            cameraDeviceWrapper.closeWithTrace()
-            cameraDevice.closeWithTrace()
+            camera2DeviceCloser.closeCamera(
+                cameraDeviceWrapper,
+                cameraDevice,
+                androidCameraState = this,
+            )
             _state.value = computeClosedState(closeInfo)
         }
     }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
index 06e4e27..8194f28 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/VirtualCameraManager.kt
@@ -50,7 +50,10 @@
 
 internal object RequestCloseAll : CameraRequest()
 
-private const val requestQueueDepth = 8
+// A queue depth of 32 was deemed necessary in b/276051078 where a flood of requests can cause the
+// queue depth to go over 8. In the long run, we can perhaps look into refactoring and
+// reimplementing the request queue in a more robust way.
+private const val requestQueueDepth = 32
 
 @Suppress("EXPERIMENTAL_API_USAGE")
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
index 710b044..522cf53 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/config/Camera2Component.kt
@@ -29,6 +29,8 @@
 import androidx.camera.camera2.pipe.compat.Camera2CameraStatusMonitor
 import androidx.camera.camera2.pipe.compat.Camera2CaptureSequenceProcessorFactory
 import androidx.camera.camera2.pipe.compat.Camera2CaptureSessionsModule
+import androidx.camera.camera2.pipe.compat.Camera2DeviceCloser
+import androidx.camera.camera2.pipe.compat.Camera2DeviceCloserImpl
 import androidx.camera.camera2.pipe.compat.Camera2ErrorProcessor
 import androidx.camera.camera2.pipe.compat.Camera2MetadataCache
 import androidx.camera.camera2.pipe.compat.Camera2MetadataProvider
@@ -76,6 +78,11 @@
     abstract fun bindCameraStatusMonitor(
         camera2CameraStatusMonitor: Camera2CameraStatusMonitor
     ): CameraStatusMonitor
+
+    @Binds
+    abstract fun bindCamera2DeviceCloser(
+        camera2CameraDeviceCloser: Camera2DeviceCloserImpl
+    ): Camera2DeviceCloser
 }
 
 @Scope
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
index 1def65c..f1360d3 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
@@ -187,7 +187,7 @@
         afRegions?.let { extra3AParams.put(CaptureRequest.CONTROL_AF_REGIONS, it.toTypedArray()) }
         awbRegions?.let { extra3AParams.put(CaptureRequest.CONTROL_AWB_REGIONS, it.toTypedArray()) }
 
-        if (!graphProcessor.submit(extra3AParams)) {
+        if (!graphProcessor.trySubmit(extra3AParams)) {
             graphListener3A.removeListener(listener)
             return CompletableDeferred(result3ASubmitFailed)
         }
@@ -245,7 +245,7 @@
         // a single request with TRIGGER = TRIGGER_CANCEL so that af can start a fresh scan.
         if (afLockBehaviorSanitized.shouldUnlockAf()) {
             debug { "lock3A - sending a request to unlock af first." }
-            if (!graphProcessor.submit(parameterForAfTriggerCancel)) {
+            if (!graphProcessor.trySubmit(parameterForAfTriggerCancel)) {
                 return CompletableDeferred(result3ASubmitFailed)
             }
         }
@@ -333,7 +333,7 @@
         // a single request with TRIGGER = TRIGGER_CANCEL so that af can start a fresh scan.
         if (afSanitized == true) {
             debug { "unlock3A - sending a request to unlock af first." }
-            if (!graphProcessor.submit(parameterForAfTriggerCancel)) {
+            if (!graphProcessor.trySubmit(parameterForAfTriggerCancel)) {
                 debug { "unlock3A - request to unlock af failed, returning early." }
                 return CompletableDeferred(result3ASubmitFailed)
             }
@@ -373,7 +373,7 @@
         graphListener3A.addListener(listener)
 
         debug { "lock3AForCapture - sending a request to trigger ae precapture metering and af." }
-        if (!graphProcessor.submit(parametersForAePrecaptureAndAfTrigger)) {
+        if (!graphProcessor.trySubmit(parametersForAePrecaptureAndAfTrigger)) {
             debug {
                 "lock3AForCapture - request to trigger ae precapture metering and af failed, " +
                     "returning early."
@@ -401,7 +401,7 @@
      */
     private suspend fun unlock3APostCaptureAndroidLAndBelow(): Deferred<Result3A> {
         debug { "unlock3AForCapture - sending a request to cancel af and turn on ae." }
-        if (!graphProcessor.submit(
+        if (!graphProcessor.trySubmit(
                 mapOf(CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_CANCEL, CONTROL_AE_LOCK to true)
             )
         ) {
@@ -415,7 +415,10 @@
         graphListener3A.addListener(listener)
 
         debug { "unlock3AForCapture - sending a request to turn off ae." }
-        if (!graphProcessor.submit(mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false))) {
+        if (!graphProcessor.trySubmit(
+                mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false)
+            )
+        ) {
             debug { "unlock3AForCapture - request to unlock ae failed." }
             graphListener3A.removeListener(listener)
             return CompletableDeferred(result3ASubmitFailed)
@@ -438,7 +441,7 @@
                 CONTROL_AE_PRECAPTURE_TRIGGER to
                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
             )
-        if (!graphProcessor.submit(parametersForAePrecaptureAndAfCancel)) {
+        if (!graphProcessor.trySubmit(parametersForAePrecaptureAndAfCancel)) {
             debug {
                 "unlock3APostCapture - request to reset af and ae precapture metering failed, " +
                     "returning early."
@@ -511,7 +514,7 @@
         }
 
         debug { "lock3A - submitting a request to lock af." }
-        val submitSuccess = graphProcessor.submit(parameterForAfTriggerStart)
+        val submitSuccess = graphProcessor.trySubmit(parameterForAfTriggerStart)
 
         lastAeMode?.let {
             graphState3A.update(aeMode = it)
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
index 355643f..e195621 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/GraphProcessor.kt
@@ -38,6 +38,7 @@
 import androidx.camera.camera2.pipe.formatForLogs
 import androidx.camera.camera2.pipe.putAllMetadata
 import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -55,7 +56,31 @@
 
     fun submit(request: Request)
     fun submit(requests: List<Request>)
-    suspend fun submit(parameters: Map<*, Any?>): Boolean
+
+    /**
+     * This tries to submit a list of parameters — essentially a list of request settings usually
+     * from 3A methods. It does this by setting the given parameters onto the current repeating
+     * request on a best-effort basis.
+     *
+     * If the CameraGraph hasn't been started yet, or we haven't yet submitted a repeating request,
+     * the method will suspend until we've met the criteria and only then submits the parameters.
+     *
+     * This behavior is required if users call 3A methods immediately after start. For example:
+     *
+     * ```
+     * cameraGraph.start()
+     * cameraGraph.acquireSession().use {
+     *     it.startRepeating(request)
+     *     it.lock3A(...)
+     * }
+     * ```
+     *
+     * Under this scenario, developers should reasonably expect things to work, and therefore
+     * the implementation handles this on a best-effort basis for the developer.
+     *
+     * Please read b/263211462 for more context.
+     */
+    suspend fun trySubmit(parameters: Map<*, Any?>): Boolean
 
     fun startRepeating(request: Request)
     fun stopRepeating()
@@ -114,6 +139,12 @@
     @GuardedBy("lock")
     private var closed = false
 
+    @GuardedBy("lock")
+    private var pendingParameters: Map<*, Any?>? = null
+
+    @GuardedBy("lock")
+    private var pendingParametersDeferred: CompletableDeferred<Boolean>? = null
+
     private val _graphState = MutableStateFlow<GraphState>(GraphStateStopped)
 
     override val graphState: StateFlow<GraphState>
@@ -248,11 +279,12 @@
     }
 
     /** Submit a request to the camera using only the current repeating request. */
-    override suspend fun submit(parameters: Map<*, Any?>): Boolean =
+    override suspend fun trySubmit(parameters: Map<*, Any?>): Boolean =
         withContext(threads.lightweightDispatcher) {
             val processor: GraphRequestProcessor?
             val request: Request?
             val requiredParameters: MutableMap<Any, Any?> = mutableMapOf()
+            var deferredResult: CompletableDeferred<Boolean>? = null
 
             synchronized(lock) {
                 if (closed) return@withContext false
@@ -262,10 +294,20 @@
                 requiredParameters.putAllMetadata(parameters.toMutableMap())
                 graphState3A.writeTo(requiredParameters)
                 requiredParameters.putAllMetadata(cameraGraphConfig.requiredParameters)
+
+                if (processor == null || request == null) {
+                    // If a previous set of parameters haven't been submitted yet, consider it stale
+                    pendingParametersDeferred?.complete(false)
+
+                    debug { "Holding parameters to be submitted later" }
+                    deferredResult = CompletableDeferred<Boolean>()
+                    pendingParametersDeferred = deferredResult
+                    pendingParameters = requiredParameters
+                }
             }
 
             return@withContext when {
-                processor == null || request == null -> false
+                processor == null || request == null -> deferredResult?.await() == true
                 else ->
                     processor.submit(
                         isRepeating = false,
@@ -389,6 +431,7 @@
                     synchronized(lock) {
                         if (processor === _requestProcessor) {
                             currentRepeatingRequest = request
+                            trySubmitPendingParameters(processor, request)
                         }
                     }
                     succeededIndex = index
@@ -411,6 +454,25 @@
         }
     }
 
+    @GuardedBy("lock")
+    private fun trySubmitPendingParameters(processor: GraphRequestProcessor, request: Request) {
+        val parameters = pendingParameters
+        val deferred = pendingParametersDeferred
+        if (parameters != null && deferred != null) {
+            val resubmitResult = processor.submit(
+                isRepeating = false,
+                requests = listOf(request),
+                defaultParameters = cameraGraphConfig.defaultParameters,
+                requiredParameters = parameters,
+                listeners = graphListeners
+            )
+            deferred.complete(resubmitResult)
+
+            pendingParameters = null
+            pendingParametersDeferred = null
+        }
+    }
+
     private fun submitLoop() {
         var burst: List<Request>
         var processor: GraphRequestProcessor
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/SurfaceGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/SurfaceGraph.kt
index 70feb5d..5305012 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/SurfaceGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/SurfaceGraph.kt
@@ -51,7 +51,7 @@
     private val surfaceUsageMap: MutableMap<Surface, AutoCloseable> = mutableMapOf()
 
     @GuardedBy("lock")
-    private val closed: Boolean = false
+    private var closed: Boolean = false
 
     operator fun set(streamId: StreamId, surface: Surface?) {
         val closeable =
@@ -104,6 +104,7 @@
                 if (closed) {
                     return
                 }
+                closed = true
                 surfaceMap.clear()
                 val tokensToClose = surfaceUsageMap.values.toList()
                 surfaceUsageMap.clear()
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpenerTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpenerTest.kt
index 6e1716c..a714105 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpenerTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/RetryingCameraStateOpenerTest.kt
@@ -33,6 +33,7 @@
 import androidx.camera.camera2.pipe.core.TimestampNs
 import androidx.camera.camera2.pipe.core.Timestamps
 import androidx.camera.camera2.pipe.internal.CameraErrorListener
+import androidx.camera.camera2.pipe.testing.FakeCamera2DeviceCloser
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.camera2.pipe.testing.FakeTimeSource
 import androidx.camera.camera2.pipe.testing.RobolectricCameraPipeTestRunner
@@ -76,6 +77,7 @@
         }
 
     private val fakeTimeSource = FakeTimeSource()
+    private val cameraDeviceCloser = FakeCamera2DeviceCloser()
 
     // TODO(lnishan): Consider mocking this object when Mockito works well with value classes.
     private val fakeCameraErrorListener =
@@ -96,6 +98,7 @@
             cameraOpener,
             camera2MetadataProvider,
             fakeCameraErrorListener,
+            cameraDeviceCloser,
             fakeTimeSource,
             cameraInteropConfig = null,
         )
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
index 75a220d..af52872 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/VirtualCameraTest.kt
@@ -21,12 +21,14 @@
 import android.os.Looper.getMainLooper
 import androidx.camera.camera2.pipe.CameraError
 import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.RequestTemplate
 import androidx.camera.camera2.pipe.core.SystemTimeSource
 import androidx.camera.camera2.pipe.core.TimeSource
 import androidx.camera.camera2.pipe.core.Timestamps
 import androidx.camera.camera2.pipe.core.Token
 import androidx.camera.camera2.pipe.graph.GraphListener
 import androidx.camera.camera2.pipe.internal.CameraErrorListener
+import androidx.camera.camera2.pipe.testing.FakeCamera2DeviceCloser
 import androidx.camera.camera2.pipe.testing.RobolectricCameraPipeTestRunner
 import androidx.camera.camera2.pipe.testing.RobolectricCameras
 import com.google.common.truth.Truth.assertThat
@@ -126,22 +128,24 @@
         // This tests that a listener attached to the virtualCamera.state property will receive all
         // of the events, starting from CameraStateUnopened.
         val virtualCamera = VirtualCameraState(cameraId, graphListener)
+        val androidCameraDevice = AndroidCameraDevice(
+            testCamera.metadata,
+            testCamera.cameraDevice,
+            testCamera.cameraId,
+            cameraErrorListener,
+        )
+        val cameraStateClosing = CameraStateClosing()
+        val cameraStateClosed =
+            CameraStateClosed(
+                cameraId,
+                ClosedReason.CAMERA2_ERROR,
+                cameraErrorCode = CameraError.ERROR_CAMERA_SERVICE
+            )
         val states =
             listOf(
-                CameraStateOpen(
-                    AndroidCameraDevice(
-                        testCamera.metadata,
-                        testCamera.cameraDevice,
-                        testCamera.cameraId,
-                        cameraErrorListener,
-                    )
-                ),
-                CameraStateClosing(),
-                CameraStateClosed(
-                    cameraId,
-                    ClosedReason.CAMERA2_ERROR,
-                    cameraErrorCode = CameraError.ERROR_CAMERA_SERVICE
-                )
+                CameraStateOpen(androidCameraDevice),
+                cameraStateClosing,
+                cameraStateClosed
             )
 
         val events = mutableListOf<CameraState>()
@@ -158,8 +162,54 @@
         advanceUntilIdle()
         job.cancelAndJoin()
 
-        val expectedStates = listOf(CameraStateUnopened).plus(states)
-        assertThat(events).containsExactlyElementsIn(expectedStates)
+        assertThat(events[0]).isSameInstanceAs(CameraStateUnopened)
+
+        assertThat(events[1]).isInstanceOf(CameraStateOpen::class.java)
+        val deviceWrapper = (events[1] as CameraStateOpen).cameraDevice
+        assertThat(deviceWrapper).isInstanceOf(VirtualAndroidCameraDevice::class.java)
+        val androidCameraStateInside =
+            (deviceWrapper as VirtualAndroidCameraDevice).androidCameraDevice
+
+        assertThat(androidCameraStateInside).isSameInstanceAs(androidCameraDevice)
+        assertThat(events[2]).isSameInstanceAs(cameraStateClosing)
+        assertThat(events[3]).isSameInstanceAs(cameraStateClosed)
+    }
+
+    @Test
+    fun virtualAndroidCameraDeviceRejectsCallsWhenVirtualCameraStateIsDisconnected() = runTest {
+        val virtualCamera = VirtualCameraState(cameraId, graphListener)
+        val cameraState =
+            flowOf(
+                CameraStateOpen(
+                    AndroidCameraDevice(
+                        testCamera.metadata,
+                        testCamera.cameraDevice,
+                        testCamera.cameraId,
+                        cameraErrorListener,
+                    )
+                )
+            )
+        virtualCamera.connect(
+            cameraState,
+            object : Token {
+                override fun release(): Boolean {
+                    return true
+                }
+            })
+
+        virtualCamera.state.first { it !is CameraStateUnopened }
+
+        val virtualCameraState = virtualCamera.value
+        assertThat(virtualCameraState).isInstanceOf(CameraStateOpen::class.java)
+        val deviceWrapper = (virtualCameraState as CameraStateOpen).cameraDevice
+        assertThat(deviceWrapper).isInstanceOf(VirtualAndroidCameraDevice::class.java)
+
+        val virtualAndroidCameraState = deviceWrapper as VirtualAndroidCameraDevice
+        val result1 = virtualAndroidCameraState.createCaptureRequest(RequestTemplate(2))
+        virtualCamera.disconnect()
+        val result2 = virtualAndroidCameraState.createCaptureRequest(RequestTemplate(2))
+        assertThat(result1).isNotNull()
+        assertThat(result2).isNull()
     }
 }
 
@@ -170,6 +220,7 @@
     private val cameraId = RobolectricCameras.create()
     private val testCamera = RobolectricCameras.open(cameraId)
     private val timeSource: TimeSource = SystemTimeSource()
+    private val cameraDeviceCloser = FakeCamera2DeviceCloser()
     private val now = Timestamps.now(timeSource)
     private val cameraErrorListener = object : CameraErrorListener {
         var lastCameraId: CameraId? = null
@@ -200,7 +251,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         assertThat(listener.state.value).isInstanceOf(CameraStateUnopened.javaClass)
@@ -246,7 +298,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         listener.onDisconnected(testCamera.cameraDevice)
@@ -268,7 +321,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         listener.close()
@@ -287,7 +341,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         listener.closeWith(IllegalArgumentException("Test Exception"))
@@ -306,7 +361,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         listener.onError(testCamera.cameraDevice, CameraDevice.StateCallback.ERROR_CAMERA_SERVICE)
@@ -327,7 +383,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser,
             )
 
         listener.onOpened(testCamera.cameraDevice)
@@ -349,7 +406,8 @@
                 attemptNumber = 1,
                 attemptTimestampNanos = now,
                 timeSource,
-                cameraErrorListener
+                cameraErrorListener,
+                cameraDeviceCloser
             )
 
         listener.onError(testCamera.cameraDevice, CameraDevice.StateCallback.ERROR_CAMERA_SERVICE)
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphProcessorTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphProcessorTest.kt
index 29210c7..d95bfd2 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphProcessorTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/GraphProcessorTest.kt
@@ -18,6 +18,7 @@
 
 import android.graphics.SurfaceTexture
 import android.hardware.camera2.CaptureRequest
+import android.hardware.camera2.CaptureRequest.CONTROL_AE_LOCK
 import android.os.Build
 import android.view.Surface
 import androidx.camera.camera2.pipe.CameraError
@@ -33,6 +34,7 @@
 import androidx.camera.camera2.pipe.testing.RobolectricCameraPipeTestRunner
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.firstOrNull
@@ -430,6 +432,67 @@
     }
 
     @Test
+    fun graphProcessorResubmitsParametersAfterGraphStarts() = runTest {
+        val graphProcessor =
+            GraphProcessorImpl(
+                FakeThreads.fromTestScope(this),
+                FakeGraphConfigs.graphConfig,
+                graphState3A,
+                this,
+                arrayListOf(globalListener)
+            )
+
+        val result = async {
+            graphProcessor.trySubmit(mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false))
+        }
+        advanceUntilIdle()
+
+        graphProcessor.onGraphStarted(graphRequestProcessor1)
+        graphProcessor.startRepeating(request1)
+        advanceUntilIdle()
+
+        assertThat(result.await()).isTrue()
+    }
+
+    @Test
+    fun graphProcessorSubmitsLatestParametersWhenSubmittedTwiceBeforeGraphStarts() = runTest {
+        val graphProcessor =
+            GraphProcessorImpl(
+                FakeThreads.fromTestScope(this),
+                FakeGraphConfigs.graphConfig,
+                graphState3A,
+                this,
+                arrayListOf(globalListener)
+            )
+
+        val result1 = async {
+            graphProcessor.trySubmit(mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false))
+        }
+        advanceUntilIdle()
+        val result2 = async {
+            graphProcessor.trySubmit(mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to true))
+        }
+        advanceUntilIdle()
+
+        graphProcessor.onGraphStarted(graphRequestProcessor1)
+        advanceUntilIdle()
+
+        graphProcessor.startRepeating(request1)
+        advanceUntilIdle()
+
+        val event1 = fakeProcessor1.nextEvent()
+        assertThat(event1.requestSequence?.repeating).isTrue()
+        val event2 = fakeProcessor1.nextEvent()
+        assertThat(event2.requestSequence?.repeating).isFalse()
+        assertThat(
+            event2.requestSequence?.requestMetadata?.get(request1)?.get(CONTROL_AE_LOCK)
+        ).isTrue()
+
+        assertThat(result1.await()).isFalse()
+        assertThat(result2.await()).isTrue()
+    }
+
+    @Test
     fun graphProcessorChangesGraphStateOnError() = runTest {
         val graphProcessor =
             GraphProcessorImpl(
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCamera2DeviceCloser.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCamera2DeviceCloser.kt
new file mode 100644
index 0000000..cfcc500
--- /dev/null
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCamera2DeviceCloser.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.camera2.pipe.testing
+
+import android.hardware.camera2.CameraDevice
+import androidx.camera.camera2.pipe.compat.AndroidCameraState
+import androidx.camera.camera2.pipe.compat.Camera2DeviceCloser
+import androidx.camera.camera2.pipe.compat.CameraDeviceWrapper
+
+internal class FakeCamera2DeviceCloser : Camera2DeviceCloser {
+    override fun closeCamera(
+        cameraDeviceWrapper: CameraDeviceWrapper?,
+        cameraDevice: CameraDevice?,
+        androidCameraState: AndroidCameraState,
+    ) {
+        cameraDeviceWrapper?.onDeviceClosed()
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
index 128e70c..6f450b9 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeGraphProcessor.kt
@@ -71,7 +71,7 @@
         _requestQueue.add(requests)
     }
 
-    override suspend fun submit(parameters: Map<*, Any?>): Boolean {
+    override suspend fun trySubmit(parameters: Map<*, Any?>): Boolean {
         if (closed) {
             return false
         }
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
index 3c0881fc..723c967 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
@@ -76,7 +76,6 @@
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.StreamSpec;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.core.resolutionselector.HighResolution;
 import androidx.camera.core.resolutionselector.ResolutionSelector;
 import androidx.camera.testing.CameraUtil;
 import androidx.camera.testing.HandlerUtil;
@@ -1076,8 +1075,8 @@
 
         // Creates a test use case with high resolution enabled.
         ResolutionSelector highResolutionSelector =
-                new ResolutionSelector.Builder().setHighResolutionEnabledFlags(
-                        HighResolution.FLAG_DEFAULT_MODE_ON).build();
+                new ResolutionSelector.Builder().setHighResolutionEnabledFlag(
+                        ResolutionSelector.HIGH_RESOLUTION_FLAG_ON).build();
         FakeUseCaseConfig.Builder configBuilder =
                 new FakeUseCaseConfig.Builder().setSessionOptionUnpacker(
                         new Camera2SessionOptionUnpacker()).setTargetName(
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2EncoderProfilesProviderTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2EncoderProfilesProviderTest.kt
index 4376357..81c3054 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2EncoderProfilesProviderTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2EncoderProfilesProviderTest.kt
@@ -187,13 +187,16 @@
     }
 
     private fun skipTestOnDevicesWithProblematicBuild() {
-        // Skip test for b/265613005 and b/223439995
+        // Skip test for b/265613005, b/223439995 and b/277174217
         val hasVideoProfilesQuirk = DeviceQuirks.get(InvalidVideoProfilesQuirk::class.java) != null
-        val isProblematicCuttlefishBuild =
-            Build.MODEL.contains("Cuttlefish") && Build.ID.startsWith("TP1A")
         assumeFalse(
             "Skip test with null VideoProfile issue. Unable to test.",
-            hasVideoProfilesQuirk || isProblematicCuttlefishBuild
+            hasVideoProfilesQuirk || isProblematicCuttlefishBuild()
         )
     }
+
+    private fun isProblematicCuttlefishBuild(): Boolean {
+        return Build.MODEL.contains("Cuttlefish", true) &&
+            (Build.ID.startsWith("TP1A", true) || Build.ID.startsWith("TSE4", true))
+    }
 }
\ No newline at end of file
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index 0ed3b9a..088aa5d 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -1185,7 +1185,7 @@
         Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
                 mUseCaseAttachState.getAttachedSessionConfigs(),
-                streamUseCaseMap, mCameraCharacteristicsCompat, false);
+                streamUseCaseMap, mCameraCharacteristicsCompat, true);
 
         mCaptureSession.setStreamUseCaseMap(streamUseCaseMap);
 
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java
index 66ce64d..da4070a 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java
@@ -115,7 +115,7 @@
         if (captureType == CaptureType.PREVIEW) {
             Size previewSize = mDisplayInfoManager.getPreviewSize();
             mutableConfig.insertOption(OPTION_MAX_RESOLUTION, previewSize);
-            ResolutionStrategy resolutionStrategy = ResolutionStrategy.create(previewSize,
+            ResolutionStrategy resolutionStrategy = new ResolutionStrategy(previewSize,
                     ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER);
             mutableConfig.insertOption(OPTION_RESOLUTION_SELECTOR,
                     new ResolutionSelector.Builder().setResolutionStrategy(
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
index a5d14b5..4894b28 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
@@ -617,6 +617,11 @@
                 return -1;
             }
 
+            if (mState != State.OPENED) {
+                Logger.d(TAG, "Skipping issueRepeatingCaptureRequests due to session closed");
+                return -1;
+            }
+
             CaptureConfig captureConfig = sessionConfig.getRepeatingCaptureConfig();
             if (captureConfig.getSurfaces().isEmpty()) {
                 Logger.d(TAG, "Skipping issueRepeatingCaptureRequests for no surface.");
@@ -691,6 +696,10 @@
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     int issueBurstCaptureRequest(List<CaptureConfig> captureConfigs) {
         synchronized (mSessionLock) {
+            if (mState != State.OPENED) {
+                Logger.d(TAG, "Skipping issueBurstCaptureRequest due to session closed");
+                return -1;
+            }
             if (captureConfigs.isEmpty()) {
                 return -1;
             }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
index c4dd892..334952fd 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/GuaranteedConfigurationsUtil.java
@@ -538,6 +538,81 @@
     }
 
     /**
+     * Returns the minimally guaranteed stream combinations when one or more
+     * streams are configured as a 10-bit input.
+     */
+    @NonNull
+    public static List<SurfaceCombination> get10BitSupportedCombinationList() {
+        List<SurfaceCombination> combinationList = new ArrayList<>();
+
+        // (PRIV, MAXIMUM)
+        SurfaceCombination surfaceCombination1 = new SurfaceCombination();
+        surfaceCombination1.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination1);
+
+        // (YUV, MAXIMUM)
+        SurfaceCombination surfaceCombination2 = new SurfaceCombination();
+        surfaceCombination2.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination2);
+
+        // (PRIV, PREVIEW) + (JPEG, MAXIMUM)
+        SurfaceCombination surfaceCombination3 = new SurfaceCombination();
+        surfaceCombination3.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination3.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.JPEG, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination3);
+
+        // (PRIV, PREVIEW) + (YUV, MAXIMUM)
+        SurfaceCombination surfaceCombination4 = new SurfaceCombination();
+        surfaceCombination4.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination4.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination4);
+
+        // (YUV, PREVIEW) + (YUV, MAXIMUM)
+        SurfaceCombination surfaceCombination5 = new SurfaceCombination();
+        surfaceCombination5.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW));
+        surfaceCombination5.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.MAXIMUM));
+        combinationList.add(surfaceCombination5);
+
+        // (PRIV, PREVIEW) + (PRIV, RECORD)
+        SurfaceCombination surfaceCombination6 = new SurfaceCombination();
+        surfaceCombination6.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination6.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+        combinationList.add(surfaceCombination6);
+
+        // (PRIV, PREVIEW) + (PRIV, RECORD) + (YUV, RECORD)
+        SurfaceCombination surfaceCombination7 = new SurfaceCombination();
+        surfaceCombination7.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination7.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+        surfaceCombination7.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.YUV, ConfigSize.RECORD));
+        combinationList.add(surfaceCombination7);
+
+        // (PRIV, PREVIEW) + (PRIV, RECORD) + (JPEG, RECORD)
+        SurfaceCombination surfaceCombination8 = new SurfaceCombination();
+        surfaceCombination8.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.PREVIEW));
+        surfaceCombination8.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.PRIV, ConfigSize.RECORD));
+        surfaceCombination8.addSurfaceConfig(
+                SurfaceConfig.create(ConfigType.JPEG, ConfigSize.RECORD));
+        combinationList.add(surfaceCombination8);
+
+        return combinationList;
+    }
+
+    /**
      * Returns the at least supported stream combinations for concurrent cameras.
      */
     @NonNull
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 33403aa..c2c5c32 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -24,6 +24,7 @@
 import static androidx.camera.core.internal.utils.SizeUtil.RESOLUTION_VGA;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
@@ -35,6 +36,7 @@
 import android.util.Size;
 
 import androidx.annotation.DoNotInline;
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
@@ -45,6 +47,7 @@
 import androidx.camera.camera2.internal.compat.workaround.ExtraSupportedSurfaceCombinationsContainer;
 import androidx.camera.camera2.internal.compat.workaround.ResolutionCorrector;
 import androidx.camera.core.CameraUnavailableException;
+import androidx.camera.core.DynamicRange;
 import androidx.camera.core.impl.AttachedSurfaceInfo;
 import androidx.camera.core.impl.CameraMode;
 import androidx.camera.core.impl.ImageFormatConstants;
@@ -57,6 +60,10 @@
 import androidx.camera.core.internal.utils.SizeUtil;
 import androidx.core.util.Preconditions;
 
+import com.google.auto.value.AutoValue;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -79,9 +86,10 @@
     private final List<SurfaceCombination> mSurfaceCombinations = new ArrayList<>();
     private final List<SurfaceCombination> mUltraHighSurfaceCombinations = new ArrayList<>();
     private final List<SurfaceCombination> mConcurrentSurfaceCombinations = new ArrayList<>();
-
-    private Map<Integer, List<SurfaceCombination>> mCameraModeToSupportedCombinationsMap =
-            new HashMap<>();
+    private final Map<FeatureSettings, List<SurfaceCombination>>
+            mFeatureSettingsToSupportedCombinationsMap = new HashMap<>();
+    private final List<SurfaceCombination> mSurfaceCombinations10Bit = new ArrayList<>();
+    boolean mIs10BitSupported = false;
     private final String mCameraId;
     private final CamcorderProfileHelper mCamcorderProfileHelper;
     private final CameraCharacteristicsCompat mCharacteristics;
@@ -99,6 +107,10 @@
     private final DisplayInfoManager mDisplayInfoManager;
     private final ResolutionCorrector mResolutionCorrector = new ResolutionCorrector();
 
+    @IntDef({DynamicRange.BIT_DEPTH_8_BIT, DynamicRange.BIT_DEPTH_10_BIT})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface RequiredMaxBitDepth {}
+
     SupportedSurfaceCombination(@NonNull Context context, @NonNull String cameraId,
             @NonNull CameraManagerCompat cameraManagerCompat,
             @NonNull CamcorderProfileHelper camcorderProfileHelper)
@@ -133,6 +145,10 @@
                         == CameraCharacteristics
                         .REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
                     mIsUltraHighResolutionSensorSupported = true;
+                } else if (capability
+                        == CameraCharacteristics
+                        .REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
+                    mIs10BitSupported = true;
                 }
             }
         }
@@ -149,6 +165,10 @@
             generateConcurrentSupportedCombinationList();
         }
 
+        if (mIs10BitSupported) {
+            generate10BitSupportedCombinationList();
+        }
+
         generateSurfaceSizeDefinition();
         checkCustomization();
     }
@@ -169,17 +189,18 @@
      * Check whether the input surface configuration list is under the capability of any combination
      * of this object.
      *
-     * @param cameraMode        the working camera mode.
+     * @param featureSettings  the settings for the camera's features/capabilities.
      * @param surfaceConfigList the surface configuration list to be compared
+     *
      * @return the check result that whether it could be supported
      */
     boolean checkSupported(
-            @CameraMode.Mode int cameraMode,
+            @NonNull FeatureSettings featureSettings,
             List<SurfaceConfig> surfaceConfigList) {
         boolean isSupported = false;
 
-        for (SurfaceCombination surfaceCombination : getSurfaceCombinationsByCameraMode(
-                cameraMode)) {
+        for (SurfaceCombination surfaceCombination : getSurfaceCombinationsByFeatureSettings(
+                featureSettings)) {
             isSupported = surfaceCombination.isSupported(surfaceConfigList);
 
             if (isSupported) {
@@ -191,30 +212,39 @@
     }
 
     /**
-     * Returns the supported surface combinations according to the specified camera mode.
+     * Returns the supported surface combinations according to the specified feature
+     * settings.
      */
-    private List<SurfaceCombination> getSurfaceCombinationsByCameraMode(
-            @CameraMode.Mode int cameraMode) {
-        if (mCameraModeToSupportedCombinationsMap.containsKey(cameraMode)) {
-            return mCameraModeToSupportedCombinationsMap.get(cameraMode);
+    private List<SurfaceCombination> getSurfaceCombinationsByFeatureSettings(
+            @NonNull FeatureSettings featureSettings) {
+        if (mFeatureSettingsToSupportedCombinationsMap.containsKey(featureSettings)) {
+            return mFeatureSettingsToSupportedCombinationsMap.get(featureSettings);
         }
 
         List<SurfaceCombination> supportedSurfaceCombinations = new ArrayList<>();
 
-        switch (cameraMode) {
-            case CameraMode.CONCURRENT_CAMERA:
-                supportedSurfaceCombinations = mConcurrentSurfaceCombinations;
-                break;
-            case CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA:
-                supportedSurfaceCombinations.addAll(mUltraHighSurfaceCombinations);
-                supportedSurfaceCombinations.addAll(mSurfaceCombinations);
-                break;
-            default:
-                supportedSurfaceCombinations.addAll(mSurfaceCombinations);
-                break;
+        if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_8_BIT) {
+            switch (featureSettings.getCameraMode()) {
+                case CameraMode.CONCURRENT_CAMERA:
+                    supportedSurfaceCombinations = mConcurrentSurfaceCombinations;
+                    break;
+                case CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA:
+                    supportedSurfaceCombinations.addAll(mUltraHighSurfaceCombinations);
+                    supportedSurfaceCombinations.addAll(mSurfaceCombinations);
+                    break;
+                default:
+                    supportedSurfaceCombinations.addAll(mSurfaceCombinations);
+                    break;
+            }
+        } else if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_10_BIT) {
+            // For 10-bit outputs, only the default camera mode is currently supported.
+            if (featureSettings.getCameraMode() == CameraMode.DEFAULT) {
+                supportedSurfaceCombinations.addAll(mSurfaceCombinations10Bit);
+            }
         }
 
-        mCameraModeToSupportedCombinationsMap.put(cameraMode, supportedSurfaceCombinations);
+        mFeatureSettingsToSupportedCombinationsMap.put(featureSettings,
+                supportedSurfaceCombinations);
 
         return supportedSurfaceCombinations;
     }
@@ -460,8 +490,9 @@
      * @return the suggested stream specifications, which is a mapping from UseCaseConfig to the
      * suggested stream specification.
      * @throws IllegalArgumentException if the suggested solution for newUseCaseConfigs cannot be
-     *                                  found. This may be due to no available output size or no
-     *                                  available surface combination.
+     *                                  found. This may be due to no available output size, no
+     *                                  available surface combination, or requiring an
+     *                                  unsupported combination of camera features.
      */
     @NonNull
     Map<UseCaseConfig<?>, StreamSpec> getSuggestedStreamSpecifications(
@@ -477,7 +508,20 @@
 
         List<UseCaseConfig<?>> newUseCaseConfigs = new ArrayList<>(
                 newUseCaseConfigsSupportedSizeMap.keySet());
-        // Use the small size (640x480) for new use cases to check whether there is any possible
+
+        int requiredMaxBitDepth = getRequiredMaxBitDepth(attachedSurfaces,
+                newUseCaseConfigsSupportedSizeMap);
+        FeatureSettings featureSettings = FeatureSettings.of(cameraMode, requiredMaxBitDepth);
+        // TODO(b/267200298): Resolve and verify all dynamic ranges
+        if (cameraMode != CameraMode.DEFAULT
+                && requiredMaxBitDepth == DynamicRange.BIT_DEPTH_10_BIT) {
+            throw new IllegalArgumentException(String.format("No supported surface combination is "
+                    + "found for camera device - Id : %s. Ten bit dynamic range is not currently "
+                    + "supported in %s camera mode.", mCameraId,
+                    CameraMode.toLabelString(cameraMode)));
+        }
+
+            // Use the small size (640x480) for new use cases to check whether there is any possible
         // supported combination first
         for (UseCaseConfig<?> useCaseConfig : newUseCaseConfigs) {
             int imageFormat = useCaseConfig.getInputFormat();
@@ -489,7 +533,7 @@
                             getUpdatedSurfaceSizeDefinitionByFormat(imageFormat)));
         }
 
-        if (!checkSupported(cameraMode, surfaceConfigs)) {
+        if (!checkSupported(featureSettings, surfaceConfigs)) {
             throw new IllegalArgumentException(
                     "No supported surface combination is found for camera device - Id : "
                             + mCameraId + ".  May be attempting to bind too many use cases. "
@@ -586,7 +630,7 @@
             }
 
             // only change the saved config if you get another that has a better max fps
-            if (checkSupported(cameraMode, surfaceConfigList)) {
+            if (checkSupported(featureSettings, surfaceConfigList)) {
                 // if the config is supported by the device but doesn't meet the target framerate,
                 // save the config
                 if (savedConfigMaxFps == Integer.MAX_VALUE) {
@@ -617,14 +661,15 @@
             }
             suggestedStreamSpecMap = new HashMap<>();
             for (UseCaseConfig<?> useCaseConfig : newUseCaseConfigs) {
-                suggestedStreamSpecMap.put(
-                        useCaseConfig,
-                        targetFramerateForDevice != null
-                                ? StreamSpec.builder(savedSizes.get(useCasesPriorityOrder.indexOf(
-                                        newUseCaseConfigs.indexOf(useCaseConfig))))
-                                .setExpectedFrameRateRange(targetFramerateForDevice).build()
-                                : StreamSpec.builder(savedSizes.get(useCasesPriorityOrder.indexOf(
-                                        newUseCaseConfigs.indexOf(useCaseConfig)))).build());
+                DynamicRange dynamicRange = useCaseConfig.getDynamicRange(null);
+                Size resolutionForUseCase = savedSizes.get(
+                        useCasesPriorityOrder.indexOf(newUseCaseConfigs.indexOf(useCaseConfig)));
+                StreamSpec.Builder streamSpecBuilder = StreamSpec.builder(resolutionForUseCase)
+                        .setDynamicRange(dynamicRange == null ? DynamicRange.SDR : dynamicRange);
+                if (targetFramerateForDevice != null) {
+                    streamSpecBuilder.setExpectedFrameRateRange(targetFramerateForDevice);
+                }
+                suggestedStreamSpecMap.put(useCaseConfig, streamSpecBuilder.build());
             }
         } else {
             throw new IllegalArgumentException(
@@ -637,6 +682,27 @@
         return suggestedStreamSpecMap;
     }
 
+    @RequiredMaxBitDepth
+    private static int getRequiredMaxBitDepth(
+            @NonNull List<AttachedSurfaceInfo> attachedSurfaces,
+            @NonNull Map<UseCaseConfig<?>, List<Size>> newUseCaseConfigsSupportedSizeMap) {
+        for (AttachedSurfaceInfo attachedSurfaceInfo : attachedSurfaces) {
+            if (attachedSurfaceInfo.getDynamicRange().getBitDepth()
+                    == DynamicRange.BIT_DEPTH_10_BIT) {
+                return DynamicRange.BIT_DEPTH_10_BIT;
+            }
+        }
+        for (UseCaseConfig<?> config : newUseCaseConfigsSupportedSizeMap.keySet()) {
+            DynamicRange dynamicRange = config.getDynamicRange(null);
+            if (dynamicRange != null && dynamicRange.getBitDepth()
+                    == DynamicRange.BIT_DEPTH_10_BIT) {
+                return DynamicRange.BIT_DEPTH_10_BIT;
+            }
+        }
+
+        return DynamicRange.BIT_DEPTH_8_BIT;
+    }
+
     private List<Integer> getUseCasesPriorityOrder(List<UseCaseConfig<?>> newUseCaseConfigs) {
         List<Integer> priorityOrder = new ArrayList<>();
 
@@ -787,6 +853,11 @@
                 GuaranteedConfigurationsUtil.getConcurrentSupportedCombinationList());
     }
 
+    private void generate10BitSupportedCombinationList() {
+        mSurfaceCombinations10Bit.addAll(
+                GuaranteedConfigurationsUtil.get10BitSupportedCombinationList());
+    }
+
     private void checkCustomization() {
         // TODO(b/119466260): Integrate found feasible stream combinations into supported list
     }
@@ -1007,4 +1078,45 @@
         }
 
     }
+
+    /**
+     * A collection of feature settings related to the Camera2 capabilities exposed by
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} and device features exposed
+     * by {@link PackageManager#hasSystemFeature(String)}.
+     */
+    @AutoValue
+    abstract static class FeatureSettings {
+        @NonNull
+        static FeatureSettings of(@CameraMode.Mode int cameraMode,
+                @RequiredMaxBitDepth int requiredMaxBitDepth) {
+            return new AutoValue_SupportedSurfaceCombination_FeatureSettings(
+                    cameraMode, requiredMaxBitDepth);
+        }
+
+        /**
+         * The camera mode.
+         *
+         * <p>This involves the following mapping of mode to feature:
+         * <ul>
+         *     <li>{@link CameraMode#CONCURRENT_CAMERA} ->
+         *         {@link PackageManager#FEATURE_CAMERA_CONCURRENT}
+         *     <li>{@link CameraMode#ULTRA_HIGH_RESOLUTION_CAMERA} ->
+         *         {@link CameraCharacteristics
+         *         #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR}
+         * </ul>
+         *
+         * <p>A value of {@link CameraMode#DEFAULT} represents the camera operating in its regular
+         * capture mode.
+         */
+        abstract @CameraMode.Mode int getCameraMode();
+
+        /**
+         * The required maximum bit depth for any non-RAW stream attached to the camera.
+         *
+         * <p>A value of {@link androidx.camera.core.DynamicRange#BIT_DEPTH_10_BIT} corresponds
+         * to the camera capability
+         * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}.
+         */
+        abstract @RequiredMaxBitDepth int getRequiredMaxBitDepth();
+    }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/CameraCharacteristicsCompat.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/CameraCharacteristicsCompat.java
index 12988bd..7e00865 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/CameraCharacteristicsCompat.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/CameraCharacteristicsCompat.java
@@ -45,6 +45,9 @@
     @NonNull
     private final String mCameraId;
 
+    @Nullable
+    private StreamConfigurationMapCompat mStreamConfigurationMapCompat = null;
+
     private CameraCharacteristicsCompat(@NonNull CameraCharacteristics cameraCharacteristics,
             @NonNull String cameraId) {
         if (Build.VERSION.SDK_INT >= 28) {
@@ -125,13 +128,18 @@
      */
     @NonNull
     public StreamConfigurationMapCompat getStreamConfigurationMapCompat() {
-        StreamConfigurationMap map = get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-        if (map == null) {
-            throw new IllegalArgumentException("StreamConfigurationMap is null!");
+        if (mStreamConfigurationMapCompat == null) {
+            StreamConfigurationMap map = get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+            if (map == null) {
+                throw new IllegalArgumentException("StreamConfigurationMap is null!");
+            }
+            OutputSizesCorrector outputSizesCorrector = new OutputSizesCorrector(mCameraId, this);
+            mStreamConfigurationMapCompat =
+                    StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map,
+                            outputSizesCorrector);
         }
-        OutputSizesCorrector outputSizesCorrector = new OutputSizesCorrector(mCameraId, this);
-        return StreamConfigurationMapCompat.toStreamConfigurationMapCompat(map,
-                outputSizesCorrector);
+
+        return mStreamConfigurationMapCompat;
     }
 
     /**
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java
index 7473a30..9004597 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/StreamConfigurationMapCompat.java
@@ -26,6 +26,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.internal.compat.workaround.OutputSizesCorrector;
+import androidx.camera.core.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Helper for accessing features in {@link StreamConfigurationMap} in a backwards compatible
@@ -33,9 +37,13 @@
  */
 @RequiresApi(21)
 public class StreamConfigurationMapCompat {
+    private static final String TAG = "StreamConfigurationMapCompat";
 
     private final StreamConfigurationMapCompatImpl mImpl;
     private final OutputSizesCorrector mOutputSizesCorrector;
+    private final Map<Integer, Size[]> mCachedFormatOutputSizes = new HashMap<>();
+    private final Map<Integer, Size[]> mCachedFormatHighResolutionOutputSizes = new HashMap<>();
+    private final Map<Class<?>, Size[]> mCachedClassOutputSizes = new HashMap<>();
 
     private StreamConfigurationMapCompat(@NonNull StreamConfigurationMap map,
             @NonNull OutputSizesCorrector outputSizesCorrector) {
@@ -76,7 +84,20 @@
      */
     @Nullable
     public Size[] getOutputSizes(int format) {
-        return mOutputSizesCorrector.applyQuirks(mImpl.getOutputSizes(format), format);
+        if (mCachedFormatOutputSizes.containsKey(format)) {
+            return mCachedFormatOutputSizes.get(format).clone();
+        }
+
+        Size[] outputSizes = mImpl.getOutputSizes(format);
+
+        if (outputSizes == null || outputSizes.length == 0) {
+            Logger.w(TAG, "Retrieved output sizes array is null or empty for format " + format);
+            return outputSizes;
+        }
+
+        outputSizes = mOutputSizesCorrector.applyQuirks(outputSizes, format);
+        mCachedFormatOutputSizes.put(format, outputSizes);
+        return outputSizes.clone();
     }
 
     /**
@@ -91,7 +112,20 @@
      */
     @Nullable
     public <T> Size[] getOutputSizes(@NonNull Class<T> klass) {
-        return mOutputSizesCorrector.applyQuirks(mImpl.getOutputSizes(klass), klass);
+        if (mCachedClassOutputSizes.containsKey(klass)) {
+            return mCachedClassOutputSizes.get(klass).clone();
+        }
+
+        Size[] outputSizes = mImpl.getOutputSizes(klass);
+
+        if (outputSizes == null || outputSizes.length == 0) {
+            Logger.w(TAG, "Retrieved output sizes array is null or empty for class " + klass);
+            return outputSizes;
+        }
+
+        outputSizes = mOutputSizesCorrector.applyQuirks(outputSizes, klass);
+        mCachedClassOutputSizes.put(klass, outputSizes);
+        return outputSizes.clone();
     }
 
     /**
@@ -105,7 +139,19 @@
      */
     @Nullable
     public Size[] getHighResolutionOutputSizes(int format) {
-        return mImpl.getHighResolutionOutputSizes(format);
+        if (mCachedFormatHighResolutionOutputSizes.containsKey(format)) {
+            return mCachedFormatHighResolutionOutputSizes.get(format).clone();
+        }
+
+        Size[] outputSizes = mImpl.getHighResolutionOutputSizes(format);
+
+        // High resolution output sizes can be null.
+        if (outputSizes != null && outputSizes.length > 0) {
+            outputSizes = mOutputSizesCorrector.applyQuirks(outputSizes, format);
+        }
+
+        mCachedFormatHighResolutionOutputSizes.put(format, outputSizes);
+        return outputSizes != null ? outputSizes.clone() : null;
     }
 
     /**
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AeFpsRangeLegacyQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AeFpsRangeLegacyQuirk.java
index 5f3c1b4..5e78461 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AeFpsRangeLegacyQuirk.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AeFpsRangeLegacyQuirk.java
@@ -64,8 +64,8 @@
     /**
      * Returns the fps range whose upper is 30 and whose lower is the smallest, or null if no
      * range has an upper equal to 30.  The rational is:
-     * (1) Range upper is always 30 so that a smooth frame rate is guaranteed.
-     * (2) Range lower contains the smallest supported value so that it can adapt as much as
+     * 1. Range upper is always 30 so that a smooth frame rate is guaranteed.
+     * 2. Range lower contains the smallest supported value so that it can adapt as much as
      * possible to low light conditions.
      */
     @Nullable
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrector.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrector.java
index c2df1ce15..a1b0644 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrector.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrector.java
@@ -20,11 +20,11 @@
 import android.util.Size;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
 import androidx.camera.camera2.internal.compat.quirk.DeviceQuirks;
 import androidx.camera.camera2.internal.compat.quirk.ExtraSupportedOutputSizeQuirk;
+import androidx.camera.core.Logger;
 import androidx.camera.core.impl.utils.AspectRatioUtil;
 import androidx.camera.core.impl.utils.CompareSizesByArea;
 
@@ -42,6 +42,7 @@
  */
 @RequiresApi(21)
 public class OutputSizesCorrector {
+    private static final String TAG = "OutputSizesCorrector";
     private final String mCameraId;
     private final CameraCharacteristicsCompat mCameraCharacteristicsCompat;
 
@@ -65,108 +66,121 @@
     /**
      * Applies the output sizes related quirks onto the input sizes array.
      */
-    @Nullable
-    public Size[] applyQuirks(@Nullable Size[] sizes, int format) {
-        Size[] result = addExtraSupportedOutputSizesByFormat(sizes, format);
-        result = excludeProblematicOutputSizesByFormat(result, format);
-        return excludeOutputSizesByTargetAspectRatioWorkaround(result);
+    @NonNull
+    public Size[] applyQuirks(@NonNull Size[] sizes, int format) {
+        List<Size> sizeList = new ArrayList<>(Arrays.asList(sizes));
+        addExtraSupportedOutputSizesByFormat(sizeList, format);
+        excludeProblematicOutputSizesByFormat(sizeList, format);
+        if (sizeList.isEmpty()) {
+            Logger.w(TAG, "Sizes array becomes empty after excluding problematic output sizes.");
+        }
+        Size[] resultSizeArray = excludeOutputSizesByTargetAspectRatioWorkaround(sizeList);
+        if (resultSizeArray.length == 0) {
+            Logger.w(TAG, "Sizes array becomes empty after excluding output sizes by target "
+                    + "aspect ratio workaround.");
+        }
+        return resultSizeArray;
     }
 
     /**
      * Applies the output sizes related quirks onto the input sizes array.
      */
-    @Nullable
-    public <T> Size[] applyQuirks(@Nullable Size[] sizes, @NonNull Class<T> klass) {
-        Size[] result = addExtraSupportedOutputSizesByClass(sizes, klass);
-        result = excludeProblematicOutputSizesByClass(result, klass);
-        return excludeOutputSizesByTargetAspectRatioWorkaround(result);
+    @NonNull
+    public <T> Size[] applyQuirks(@NonNull Size[] sizes, @NonNull Class<T> klass) {
+        List<Size> sizeList = new ArrayList<>(Arrays.asList(sizes));
+        addExtraSupportedOutputSizesByClass(sizeList, klass);
+        excludeProblematicOutputSizesByClass(sizeList, klass);
+        if (sizeList.isEmpty()) {
+            Logger.w(TAG, "Sizes array becomes empty after excluding problematic output sizes.");
+        }
+        Size[] resultSizeArray = excludeOutputSizesByTargetAspectRatioWorkaround(sizeList);
+        if (resultSizeArray.length == 0) {
+            Logger.w(TAG, "Sizes array becomes empty after excluding output sizes by target "
+                    + "aspect ratio workaround.");
+        }
+        return resultSizeArray;
     }
 
     /**
      * Adds extra supported output sizes for the specified format by ExtraSupportedOutputSizeQuirk.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param format the image format to apply the workaround
      */
-    @Nullable
-    private Size[] addExtraSupportedOutputSizesByFormat(@Nullable Size[] sizes, int format) {
+    private void addExtraSupportedOutputSizesByFormat(@NonNull List<Size> sizeList, int format) {
         if (mExtraSupportedOutputSizeQuirk == null) {
-            return sizes;
+            return;
         }
 
         Size[] extraSizes = mExtraSupportedOutputSizeQuirk.getExtraSupportedResolutions(format);
-        return concatNullableSizeLists(Arrays.asList(sizes), Arrays.asList(extraSizes)).toArray(
-                new Size[0]);
+
+        if (extraSizes.length > 0) {
+            sizeList.addAll(Arrays.asList(extraSizes));
+        }
     }
 
     /**
      * Adds extra supported output sizes for the specified class by ExtraSupportedOutputSizeQuirk.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param klass the class to apply the workaround
      */
-    @Nullable
-    private <T> Size[] addExtraSupportedOutputSizesByClass(@Nullable Size[] sizes,
-            @NonNull Class<T> klass) {
+    private void addExtraSupportedOutputSizesByClass(@NonNull List<Size> sizeList,
+            @NonNull Class<?> klass) {
         if (mExtraSupportedOutputSizeQuirk == null) {
-            return sizes;
+            return;
         }
 
         Size[] extraSizes = mExtraSupportedOutputSizeQuirk.getExtraSupportedResolutions(klass);
-        return concatNullableSizeLists(Arrays.asList(sizes), Arrays.asList(extraSizes)).toArray(
-                new Size[0]);
+
+        if (extraSizes.length > 0) {
+            sizeList.addAll(Arrays.asList(extraSizes));
+        }
     }
 
     /**
      * Excludes problematic output sizes for the specified format by
      * ExcludedSupportedSizesContainer.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param format the image format to apply the workaround
      */
-    @Nullable
-    private Size[] excludeProblematicOutputSizesByFormat(@Nullable Size[] sizes, int format) {
-        if (sizes == null) {
-            return null;
-        }
-
+    private void excludeProblematicOutputSizesByFormat(@NonNull List<Size> sizeList, int format) {
         List<Size> excludedSizes = mExcludedSupportedSizesContainer.get(format);
 
-        List<Size> resultList = new ArrayList<>(Arrays.asList(sizes));
-        resultList.removeAll(excludedSizes);
-
-        if (resultList.isEmpty()) {
-            return null;
-        } else {
-            return resultList.toArray(new Size[0]);
+        if (excludedSizes.isEmpty()) {
+            return;
         }
+
+        sizeList.removeAll(excludedSizes);
     }
 
     /**
      * Excludes problematic output sizes for the specified class type by
      * ExcludedSupportedSizesContainer.
+     *
+     * @param sizeList the original sizes list which must be a mutable list
+     * @param klass the class to apply the workaround
      */
-    @Nullable
-    private <T> Size[] excludeProblematicOutputSizesByClass(@Nullable Size[] sizes,
-            @NonNull Class<T> klass) {
-        if (sizes == null) {
-            return null;
-        }
-
+    private void excludeProblematicOutputSizesByClass(@NonNull List<Size> sizeList,
+            @NonNull Class<?> klass) {
         List<Size> excludedSizes = mExcludedSupportedSizesContainer.get(klass);
 
-        List<Size> resultList = new ArrayList<>(Arrays.asList(sizes));
-        resultList.removeAll(excludedSizes);
-
-        if (resultList.isEmpty()) {
-            return null;
-        } else {
-            return resultList.toArray(new Size[0]);
+        if (excludedSizes.isEmpty()) {
+            return;
         }
+
+        sizeList.removeAll(excludedSizes);
     }
 
     /**
      * Excludes output sizes by TargetAspectRatio.
+     *
+     * @param sizeList the original sizes list
      */
-    @Nullable
-    private Size[] excludeOutputSizesByTargetAspectRatioWorkaround(@Nullable Size[] sizes) {
-        if (sizes == null) {
-            return null;
-        }
-
+    @NonNull
+    private Size[] excludeOutputSizesByTargetAspectRatioWorkaround(@NonNull List<Size> sizeList) {
         int targetAspectRatio = mTargetAspectRatio.get(mCameraId, mCameraCharacteristicsCompat);
-
         Rational ratio = null;
 
         switch (targetAspectRatio) {
@@ -177,7 +191,7 @@
                 ratio = AspectRatioUtil.ASPECT_RATIO_16_9;
                 break;
             case TargetAspectRatio.RATIO_MAX_JPEG:
-                Size maxJpegSize = Collections.max(Arrays.asList(sizes), new CompareSizesByArea());
+                Size maxJpegSize = Collections.max(sizeList, new CompareSizesByArea());
                 ratio = new Rational(maxJpegSize.getWidth(), maxJpegSize.getHeight());
                 break;
             case TargetAspectRatio.RATIO_ORIGINAL:
@@ -185,35 +199,17 @@
         }
 
         if (ratio == null) {
-            return sizes;
+            return sizeList.toArray(sizeList.toArray(new Size[0]));
         }
 
         List<Size> resultList = new ArrayList<>();
 
-        for (Size size : sizes) {
+        for (Size size : sizeList) {
             if (AspectRatioUtil.hasMatchingAspectRatio(size, ratio)) {
                 resultList.add(size);
             }
         }
 
-        if (resultList.isEmpty()) {
-            return null;
-        } else {
-            return resultList.toArray(new Size[0]);
-        }
-    }
-
-    @Nullable
-    private static List<Size> concatNullableSizeLists(@Nullable List<Size> sizeList1,
-            @Nullable List<Size> sizeList2) {
-        if (sizeList1 == null) {
-            return sizeList2;
-        } else if (sizeList2 == null) {
-            return sizeList1;
-        } else {
-            List<Size> resultList = new ArrayList<>(sizeList1);
-            resultList.addAll(sizeList2);
-            return resultList;
-        }
+        return resultList.toArray(new Size[0]);
     }
 }
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
index 669bd43..300df6d 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2CameraInfoImplTest.java
@@ -661,9 +661,9 @@
     public void cameraInfo_canReturnSupportedFpsRanges() throws CameraAccessExceptionCompat {
         init(/* hasAvailableCapabilities = */ false);
 
-        final Camera2CameraInfoImpl cameraInfo0 = new Camera2CameraInfoImpl(CAMERA0_ID,
+        CameraInfo cameraInfo0 = new Camera2CameraInfoImpl(CAMERA0_ID,
                 mCameraManagerCompat);
-        final Camera2CameraInfoImpl cameraInfo2 = new Camera2CameraInfoImpl(CAMERA2_ID,
+        CameraInfo cameraInfo2 = new Camera2CameraInfoImpl(CAMERA2_ID,
                 mCameraManagerCompat);
 
         List<Range<Integer>> resultFpsRanges0 = cameraInfo0.getSupportedFrameRateRanges();
@@ -678,7 +678,7 @@
             throws CameraAccessExceptionCompat {
         init(/* hasAvailableCapabilities = */ false);
 
-        final Camera2CameraInfoImpl cameraInfo1 = new Camera2CameraInfoImpl(CAMERA1_ID,
+        CameraInfo cameraInfo1 = new Camera2CameraInfoImpl(CAMERA1_ID,
                 mCameraManagerCompat);
 
         List<Range<Integer>> resultFpsRanges1 = cameraInfo1.getSupportedFrameRateRanges();
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
index bd2e393..09f3d72 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
@@ -23,6 +23,8 @@
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraManager
 import android.hardware.camera2.CameraMetadata
+import android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+import android.hardware.camera2.CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
 import android.hardware.camera2.params.StreamConfigurationMap
 import android.media.CamcorderProfile
 import android.media.CamcorderProfile.QUALITY_1080P
@@ -35,15 +37,21 @@
 import android.util.Size
 import android.view.WindowManager
 import androidx.camera.camera2.Camera2Config
+import androidx.camera.camera2.internal.SupportedSurfaceCombination.FeatureSettings
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
 import androidx.camera.core.CameraSelector.LensFacing
 import androidx.camera.core.CameraX
 import androidx.camera.core.CameraXConfig
+import androidx.camera.core.DynamicRange
+import androidx.camera.core.DynamicRange.BIT_DEPTH_10_BIT
+import androidx.camera.core.DynamicRange.FORMAT_HLG
+import androidx.camera.core.DynamicRange.SDR
 import androidx.camera.core.UseCase
 import androidx.camera.core.impl.AttachedSurfaceInfo
 import androidx.camera.core.impl.CameraDeviceSurfaceManager
 import androidx.camera.core.impl.CameraMode
 import androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+import androidx.camera.core.impl.ImageInputConfig
 import androidx.camera.core.impl.StreamSpec
 import androidx.camera.core.impl.SurfaceCombination
 import androidx.camera.core.impl.SurfaceConfig
@@ -186,8 +194,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLegacySupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -215,8 +227,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -227,8 +243,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -239,8 +259,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -253,8 +277,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -286,8 +314,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -300,8 +332,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -314,8 +350,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -347,8 +387,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isFalse()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isFalse()
         }
     }
 
@@ -362,8 +406,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLimitedSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -377,8 +425,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLegacySupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -392,8 +444,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getFullSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -407,8 +463,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getRAWSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -421,8 +481,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getLevel3SupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.DEFAULT, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -456,8 +520,12 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getConcurrentSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.CONCURRENT_CAMERA, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.CONCURRENT_CAMERA, DynamicRange.BIT_DEPTH_8_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -492,8 +560,14 @@
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
         GuaranteedConfigurationsUtil.getUltraHighResolutionSupportedCombinationList().forEach {
-            assertThat(supportedSurfaceCombination.checkSupported(
-                CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, it.surfaceConfigList)).isTrue()
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(
+                        CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA, DynamicRange.BIT_DEPTH_8_BIT
+                    ),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
         }
     }
 
@@ -1443,33 +1517,35 @@
     }
 
     private fun getSuggestedSpecsAndVerify(
-        useCasesExpectedResultMap: Map<UseCase, Size>,
+        useCasesExpectedSizeMap: Map<UseCase, Size>,
         attachedSurfaceInfoList: List<AttachedSurfaceInfo> = emptyList(),
         hardwareLevel: Int = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
         capabilities: IntArray? = null,
         compareWithAtMost: Boolean = false,
-        compareExpectedFps: Range<Int>? = null
+        compareExpectedFps: Range<Int>? = null,
+        cameraMode: Int = CameraMode.DEFAULT,
+        useCasesExpectedDynamicRangeMap: Map<UseCase, DynamicRange> = emptyMap()
     ) {
         setupCameraAndInitCameraX(
             hardwareLevel = hardwareLevel,
-            capabilities = capabilities
+            capabilities = capabilities,
         )
         val supportedSurfaceCombination = SupportedSurfaceCombination(
             context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
         )
 
-        val useCaseConfigMap = getUseCaseToConfigMap(useCasesExpectedResultMap.keys.toList())
+        val useCaseConfigMap = getUseCaseToConfigMap(useCasesExpectedSizeMap.keys.toList())
         val useCaseConfigToOutputSizesMap =
             getUseCaseConfigToOutputSizesMap(useCaseConfigMap.values.toList())
         val suggestedStreamSpecs = supportedSurfaceCombination.getSuggestedStreamSpecifications(
-            CameraMode.DEFAULT,
+            cameraMode,
             attachedSurfaceInfoList,
             useCaseConfigToOutputSizesMap
         )
 
-        useCasesExpectedResultMap.keys.forEach {
+        useCasesExpectedSizeMap.keys.forEach {
             val resultSize = suggestedStreamSpecs[useCaseConfigMap[it]]!!.resolution
-            val expectedSize = useCasesExpectedResultMap[it]!!
+            val expectedSize = useCasesExpectedSizeMap[it]!!
             if (!compareWithAtMost) {
                 assertThat(resultSize).isEqualTo(expectedSize)
             } else {
@@ -1477,10 +1553,19 @@
             }
 
             if (compareExpectedFps != null) {
-                assertThat(suggestedStreamSpecs[useCaseConfigMap[it]]!!.expectedFrameRateRange
-                == compareExpectedFps)
+                assertThat(
+                    suggestedStreamSpecs[useCaseConfigMap[it]]!!.expectedFrameRateRange
+                        == compareExpectedFps
+                )
             }
         }
+
+        useCasesExpectedDynamicRangeMap.keys.forEach {
+            val resultDynamicRange = suggestedStreamSpecs[useCaseConfigMap[it]]!!.dynamicRange
+            val expectedDynamicRange = useCasesExpectedDynamicRangeMap[it]
+
+            assertThat(resultDynamicRange).isEqualTo(expectedDynamicRange)
+        }
     }
 
     private fun getUseCaseToConfigMap(useCases: List<UseCase>): Map<UseCase, UseCaseConfig<*>> {
@@ -1506,6 +1591,185 @@
 
     // //////////////////////////////////////////////////////////////////////////////////////////
     //
+    // StreamSpec selection tests for DynamicRange
+    //
+    // //////////////////////////////////////////////////////////////////////////////////////////
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun check10BitDynamicRangeCombinationsSupported() {
+        setupCameraAndInitCameraX(
+            capabilities = intArrayOf(
+                REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
+            )
+        )
+        val supportedSurfaceCombination = SupportedSurfaceCombination(
+            context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
+        )
+
+        GuaranteedConfigurationsUtil.get10BitSupportedCombinationList().forEach {
+            assertThat(
+                supportedSurfaceCombination.checkSupported(
+                    FeatureSettings.of(CameraMode.DEFAULT, BIT_DEPTH_10_BIT),
+                    it.surfaceConfigList
+                )
+            ).isTrue()
+        }
+    }
+
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun check10BitDynamicRangeCombinationsSubListSupported() {
+        setupCameraAndInitCameraX(
+            capabilities = intArrayOf(
+                REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
+            )
+        )
+        val supportedSurfaceCombination = SupportedSurfaceCombination(
+            context, DEFAULT_CAMERA_ID, cameraManagerCompat!!, mockCamcorderProfileHelper
+        )
+
+        GuaranteedConfigurationsUtil.get10BitSupportedCombinationList().also {
+            assertThat(
+                isAllSubConfigListSupported(
+                    CameraMode.DEFAULT,
+                    supportedSurfaceCombination, it, BIT_DEPTH_10_BIT
+                )
+            ).isTrue()
+        }
+    }
+
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun getSupportedStreamSpecThrows_whenUsingConcurrentCameraAndSupported10BitRange() {
+        shadowOf(context.packageManager).setSystemFeature(
+            FEATURE_CAMERA_CONCURRENT, true
+        )
+        val useCase = createUseCase(
+            CaptureType.PREVIEW,
+            dynamicRange = DynamicRange.HDR_UNSPECIFIED_10_BIT
+        )
+        val useCaseExpectedSizeMap = mapOf(
+            useCase to Size(0, 0) // Should throw before verifying size
+        )
+
+        assertThrows(IllegalArgumentException::class.java) {
+            getSuggestedSpecsAndVerify(
+                useCaseExpectedSizeMap,
+                cameraMode = CameraMode.CONCURRENT_CAMERA,
+            )
+        }
+    }
+
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun getSupportedStreamSpecThrows_whenUsingUltraHighResolutionAndSupported10BitRange() {
+        shadowOf(context.packageManager).setSystemFeature(
+            FEATURE_CAMERA_CONCURRENT, true
+        )
+        val useCase = createUseCase(
+            CaptureType.PREVIEW,
+            dynamicRange = DynamicRange.HDR_UNSPECIFIED_10_BIT
+        )
+        val useCaseExpectedSizeMap = mapOf(
+            useCase to Size(0, 0) // Should throw before verifying size
+        )
+
+        assertThrows(IllegalArgumentException::class.java) {
+            getSuggestedSpecsAndVerify(
+                useCaseExpectedSizeMap,
+                cameraMode = CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA,
+            )
+        }
+    }
+
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun tenBitTable_isUsed_whenAttaching10BitUseCaseToAlreadyAttachedSdrUseCases() {
+        // JPEG use case can't be attached with an existing PRIV + YUV in the 10-bit tables
+        val useCase = createUseCase(
+            CaptureType.IMAGE_CAPTURE,
+            dynamicRange = DynamicRange(FORMAT_HLG, BIT_DEPTH_10_BIT)
+        )
+        val useCaseExpectedSizeMap = mapOf(
+            // Size would be valid for LIMITED table
+            useCase to RECORD_SIZE
+        )
+        // existing surfaces (Preview + ImageAnalysis)
+        val attachedPreview = AttachedSurfaceInfo.create(
+            SurfaceConfig.create(
+                ConfigType.PRIV,
+                ConfigSize.PREVIEW
+            ),
+            ImageFormat.PRIVATE,
+            PREVIEW_SIZE,
+            SDR,
+            /*targetFrameRate=*/null
+        )
+        val attachedAnalysis = AttachedSurfaceInfo.create(
+            SurfaceConfig.create(
+                ConfigType.YUV,
+                ConfigSize.RECORD
+            ),
+            ImageFormat.YUV_420_888,
+            RECORD_SIZE,
+            SDR,
+            /*targetFrameRate=*/null
+        )
+
+        assertThrows(IllegalArgumentException::class.java) {
+            getSuggestedSpecsAndVerify(
+                useCaseExpectedSizeMap,
+                attachedSurfaceInfoList = listOf(attachedPreview, attachedAnalysis),
+                // LIMITED allows this combination, but 10-bit table does not
+                hardwareLevel = INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+                capabilities = intArrayOf(REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)
+            )
+        }
+    }
+
+    @Config(minSdk = Build.VERSION_CODES.TIRAMISU)
+    @Test
+    fun canAttachHlgDynamicRange_toExistingSdrStreams() {
+        // JPEG use case can be attached with an existing PRIV + PRIV in the 10-bit tables
+        val useCase = createUseCase(
+            CaptureType.IMAGE_CAPTURE,
+            dynamicRange = DynamicRange(FORMAT_HLG, BIT_DEPTH_10_BIT)
+        )
+        val useCaseExpectedSizeMap = mapOf(
+            // Size is valid for 10-bit table within constraints
+            useCase to RECORD_SIZE
+        )
+        // existing surfaces (PRIV + PRIV)
+        val attachedPriv1 = AttachedSurfaceInfo.create(
+            SurfaceConfig.create(
+                ConfigType.PRIV,
+                ConfigSize.PREVIEW
+            ),
+            ImageFormat.PRIVATE,
+            PREVIEW_SIZE,
+            SDR,
+            /*targetFrameRate=*/null
+        )
+        val attachedPriv2 = AttachedSurfaceInfo.create(
+            SurfaceConfig.create(
+                ConfigType.PRIV,
+                ConfigSize.RECORD
+            ),
+            ImageFormat.YUV_420_888,
+            RECORD_SIZE,
+            SDR,
+            /*targetFrameRate=*/null
+        )
+
+        getSuggestedSpecsAndVerify(
+            useCaseExpectedSizeMap,
+            attachedSurfaceInfoList = listOf(attachedPriv1, attachedPriv2),
+            capabilities = intArrayOf(REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)
+        )
+    }
+
+    // //////////////////////////////////////////////////////////////////////////////////////////
+    //
     // Resolution selection tests for FPS settings
     //
     // //////////////////////////////////////////////////////////////////////////////////////////
@@ -1635,8 +1899,11 @@
             SurfaceConfig.create(
                 ConfigType.JPEG,
                 ConfigSize.PREVIEW
-            ), ImageFormat.JPEG,
-            Size(1280, 720), Range(40, 50)
+            ),
+            ImageFormat.JPEG,
+            Size(1280, 720),
+            SDR,
+            Range(40, 50)
         )
         getSuggestedSpecsAndVerify(
             useCaseExpectedResultMap,
@@ -1659,8 +1926,11 @@
             SurfaceConfig.create(
                 ConfigType.JPEG,
                 ConfigSize.PREVIEW
-            ), ImageFormat.JPEG,
-            Size(1280, 720), Range(40, 50)
+            ),
+            ImageFormat.JPEG,
+            Size(1280, 720),
+            SDR,
+            Range(40, 50)
         )
         getSuggestedSpecsAndVerify(
             useCaseExpectedResultMap,
@@ -1683,8 +1953,11 @@
             SurfaceConfig.create(
                 ConfigType.JPEG,
                 ConfigSize.PREVIEW
-            ), ImageFormat.JPEG,
-            Size(1280, 720), Range(40, 50)
+            ),
+            ImageFormat.JPEG,
+            Size(1280, 720),
+            SDR,
+            Range(40, 50)
         )
         getSuggestedSpecsAndVerify(
             useCaseExpectedResultMap,
@@ -2114,7 +2387,7 @@
      * resolution supported sizes of the camera. Default value is null.
      * @param capabilities the capabilities of the camera. Default value is null.
      */
-    fun setupCamera(
+    private fun setupCamera(
         cameraId: String = DEFAULT_CAMERA_ID,
         hardwareLevel: Int = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
         sensorOrientation: Int = SENSOR_ORIENTATION_90,
@@ -2290,7 +2563,8 @@
     private fun isAllSubConfigListSupported(
         cameraMode: Int = CameraMode.DEFAULT,
         supportedSurfaceCombination: SupportedSurfaceCombination,
-        combinationList: List<SurfaceCombination>
+        combinationList: List<SurfaceCombination>,
+        requiredMaxBitDepth: Int = DynamicRange.BIT_DEPTH_8_BIT
     ): Boolean {
         combinationList.forEach { combination ->
             val configList = combination.surfaceConfigList
@@ -2303,9 +2577,9 @@
                     addAll(configList)
                     removeAt(index)
                 }
-                if (!supportedSurfaceCombination.checkSupported(
-                        cameraMode, subConfigurationList
-                    )
+                val featureSettings = FeatureSettings.of(cameraMode, requiredMaxBitDepth)
+                if (!supportedSurfaceCombination
+                        .checkSupported(featureSettings, subConfigurationList)
                 ) {
                     return false
                 }
@@ -2316,16 +2590,22 @@
 
     private fun createUseCase(
         captureType: CaptureType,
-        targetFrameRate: Range<Int>? = null
+        targetFrameRate: Range<Int>? = null,
+        dynamicRange: DynamicRange? = null
     ): UseCase {
-        val builder = FakeUseCaseConfig.Builder(captureType, when (captureType) {
-            CaptureType.IMAGE_CAPTURE -> ImageFormat.JPEG
-            CaptureType.IMAGE_ANALYSIS -> ImageFormat.YUV_420_888
-            else -> INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
-        })
+        val builder = FakeUseCaseConfig.Builder(
+            captureType, when (captureType) {
+                CaptureType.IMAGE_CAPTURE -> ImageFormat.JPEG
+                CaptureType.IMAGE_ANALYSIS -> ImageFormat.YUV_420_888
+                else -> INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
+            }
+        )
         targetFrameRate?.let {
             builder.mutableConfig.insertOption(UseCaseConfig.OPTION_TARGET_FRAME_RATE, it)
         }
+        dynamicRange?.let {
+            builder.mutableConfig.insertOption(ImageInputConfig.OPTION_INPUT_DYNAMIC_RANGE, it)
+        }
         return builder.build()
     }
 
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
index 74492f9..1db209b 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/OutputSizesCorrectorTest.kt
@@ -83,7 +83,7 @@
                 Size(3088, 3088),
             ),
             ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE
-        )!!.toList()
+        ).toList()
 
         assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -120,7 +120,7 @@
                 Size(3088, 3088),
             ),
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -152,7 +152,7 @@
         )
 
         val resultList = mutableListOf<Size>().apply {
-            outputSizesCorrector.applyQuirks(outputSizes, ImageFormat.YUV_420_888)!!
+            outputSizesCorrector.applyQuirks(outputSizes, ImageFormat.YUV_420_888)
                 .forEach { size ->
                     add(size)
                 }
@@ -191,7 +191,7 @@
         val resultList = outputSizesCorrector.applyQuirks(
             outputSizes,
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         assertThat(resultList).containsExactlyElementsIn(
             listOf(
@@ -221,7 +221,7 @@
         val resultList = outputSizesCorrector.applyQuirks(
             outputSizes,
             ImageFormat.YUV_420_888
-        )!!.toList()
+        ).toList()
 
         val expectedList = if (Build.VERSION.SDK_INT == 21) {
             // non-4:3 sizes are removed
@@ -267,7 +267,7 @@
         val resultList = outputSizesCorrector.applyQuirks(
             outputSizes,
             SurfaceTexture::class.java
-        )!!.toList()
+        ).toList()
 
         val expectedList = if (Build.VERSION.SDK_INT == 21) {
             // non-4:3 sizes are removed
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/TargetAspectRatioTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/TargetAspectRatioTest.java
index a9d5195..6b52add6 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/TargetAspectRatioTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/TargetAspectRatioTest.java
@@ -110,6 +110,7 @@
         mConfig = config;
     }
 
+    @SuppressWarnings("deprecation") // legacy resolution API
     @Test
     public void getCorrectedRatio() {
         // Set up device properties
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index 62e015d..20658d2 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -47,6 +47,7 @@
     method public default int getLensFacing();
     method public int getSensorRotationDegrees();
     method public int getSensorRotationDegrees(int);
+    method public default java.util.List<android.util.Range<java.lang.Integer!>!> getSupportedFrameRateRanges();
     method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
     method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
     method public boolean hasFlashUnit();
@@ -207,6 +208,7 @@
     method public int getImageQueueDepth();
     method public int getOutputImageFormat();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public boolean isOutputImageRotationEnabled();
     method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
@@ -234,9 +236,10 @@
     method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
     method public androidx.camera.core.ImageAnalysis.Builder setOutputImageFormat(int);
     method @RequiresApi(23) public androidx.camera.core.ImageAnalysis.Builder setOutputImageRotationEnabled(boolean);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
   }
 
@@ -245,6 +248,7 @@
     method public int getFlashMode();
     method @IntRange(from=1, to=100) public int getJpegQuality();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public void setCropAspectRatio(android.util.Rational);
     method public void setFlashMode(int);
@@ -271,9 +275,10 @@
     method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
     method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
     method public androidx.camera.core.ImageCapture.Builder setJpegQuality(@IntRange(from=1, to=100) int);
-    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
-    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
   }
 
@@ -379,6 +384,7 @@
 
   @RequiresApi(21) public final class Preview extends androidx.camera.core.UseCase {
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
@@ -388,9 +394,10 @@
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
     ctor public Preview.Builder();
     method public androidx.camera.core.Preview build();
-    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.Preview.Builder setTargetName(String);
-    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.Preview.Builder setTargetRotation(int);
   }
 
@@ -510,3 +517,51 @@
 
 }
 
+package androidx.camera.core.resolutionselector {
+
+  @RequiresApi(21) public final class AspectRatioStrategy {
+    ctor public AspectRatioStrategy(int, int);
+    method public int getFallbackRule();
+    method public int getPreferredAspectRatio();
+    field public static final int FALLBACK_RULE_AUTO = 1; // 0x1
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY;
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY;
+  }
+
+  @RequiresApi(21) public interface ResolutionFilter {
+    method public java.util.List<android.util.Size!> filter(java.util.List<android.util.Size!>, int);
+  }
+
+  @RequiresApi(21) public final class ResolutionSelector {
+    method public androidx.camera.core.resolutionselector.AspectRatioStrategy getAspectRatioStrategy();
+    method public int getHighResolutionEnabledFlag();
+    method public androidx.camera.core.resolutionselector.ResolutionFilter? getResolutionFilter();
+    method public androidx.camera.core.resolutionselector.ResolutionStrategy? getResolutionStrategy();
+    field public static final int HIGH_RESOLUTION_FLAG_OFF = 0; // 0x0
+    field public static final int HIGH_RESOLUTION_FLAG_ON = 1; // 0x1
+  }
+
+  public static final class ResolutionSelector.Builder {
+    ctor public ResolutionSelector.Builder();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector build();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAspectRatioStrategy(androidx.camera.core.resolutionselector.AspectRatioStrategy);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setHighResolutionEnabledFlag(int);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionStrategy(androidx.camera.core.resolutionselector.ResolutionStrategy);
+  }
+
+  @RequiresApi(21) public final class ResolutionStrategy {
+    ctor public ResolutionStrategy(android.util.Size, int);
+    method public android.util.Size? getBoundSize();
+    method public int getFallbackRule();
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER = 2; // 0x2
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER = 1; // 0x1
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER = 4; // 0x4
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER = 3; // 0x3
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.ResolutionStrategy HIGHEST_AVAILABLE_STRATEGY;
+  }
+
+}
+
diff --git a/camera/camera-core/api/public_plus_experimental_current.txt b/camera/camera-core/api/public_plus_experimental_current.txt
index 6b3b6b1..635067b 100644
--- a/camera/camera-core/api/public_plus_experimental_current.txt
+++ b/camera/camera-core/api/public_plus_experimental_current.txt
@@ -47,6 +47,7 @@
     method public default int getLensFacing();
     method public int getSensorRotationDegrees();
     method public int getSensorRotationDegrees(int);
+    method public default java.util.List<android.util.Range<java.lang.Integer!>!> getSupportedFrameRateRanges();
     method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
     method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
     method public boolean hasFlashUnit();
@@ -222,6 +223,7 @@
     method public int getImageQueueDepth();
     method public int getOutputImageFormat();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public boolean isOutputImageRotationEnabled();
     method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
@@ -249,9 +251,10 @@
     method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
     method public androidx.camera.core.ImageAnalysis.Builder setOutputImageFormat(int);
     method @RequiresApi(23) public androidx.camera.core.ImageAnalysis.Builder setOutputImageRotationEnabled(boolean);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
   }
 
@@ -260,6 +263,7 @@
     method public int getFlashMode();
     method @IntRange(from=1, to=100) public int getJpegQuality();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public void setCropAspectRatio(android.util.Rational);
     method public void setFlashMode(int);
@@ -287,9 +291,10 @@
     method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
     method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
     method public androidx.camera.core.ImageCapture.Builder setJpegQuality(@IntRange(from=1, to=100) int);
-    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
-    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
   }
 
@@ -396,6 +401,7 @@
 
   @RequiresApi(21) public final class Preview extends androidx.camera.core.UseCase {
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
@@ -405,9 +411,10 @@
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
     ctor public Preview.Builder();
     method public androidx.camera.core.Preview build();
-    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.Preview.Builder setTargetName(String);
-    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.Preview.Builder setTargetRotation(int);
   }
 
@@ -527,3 +534,51 @@
 
 }
 
+package androidx.camera.core.resolutionselector {
+
+  @RequiresApi(21) public final class AspectRatioStrategy {
+    ctor public AspectRatioStrategy(int, int);
+    method public int getFallbackRule();
+    method public int getPreferredAspectRatio();
+    field public static final int FALLBACK_RULE_AUTO = 1; // 0x1
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY;
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY;
+  }
+
+  @RequiresApi(21) public interface ResolutionFilter {
+    method public java.util.List<android.util.Size!> filter(java.util.List<android.util.Size!>, int);
+  }
+
+  @RequiresApi(21) public final class ResolutionSelector {
+    method public androidx.camera.core.resolutionselector.AspectRatioStrategy getAspectRatioStrategy();
+    method public int getHighResolutionEnabledFlag();
+    method public androidx.camera.core.resolutionselector.ResolutionFilter? getResolutionFilter();
+    method public androidx.camera.core.resolutionselector.ResolutionStrategy? getResolutionStrategy();
+    field public static final int HIGH_RESOLUTION_FLAG_OFF = 0; // 0x0
+    field public static final int HIGH_RESOLUTION_FLAG_ON = 1; // 0x1
+  }
+
+  public static final class ResolutionSelector.Builder {
+    ctor public ResolutionSelector.Builder();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector build();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAspectRatioStrategy(androidx.camera.core.resolutionselector.AspectRatioStrategy);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setHighResolutionEnabledFlag(int);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionStrategy(androidx.camera.core.resolutionselector.ResolutionStrategy);
+  }
+
+  @RequiresApi(21) public final class ResolutionStrategy {
+    ctor public ResolutionStrategy(android.util.Size, int);
+    method public android.util.Size? getBoundSize();
+    method public int getFallbackRule();
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER = 2; // 0x2
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER = 1; // 0x1
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER = 4; // 0x4
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER = 3; // 0x3
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.ResolutionStrategy HIGHEST_AVAILABLE_STRATEGY;
+  }
+
+}
+
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index 62e015d..20658d2 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -47,6 +47,7 @@
     method public default int getLensFacing();
     method public int getSensorRotationDegrees();
     method public int getSensorRotationDegrees(int);
+    method public default java.util.List<android.util.Range<java.lang.Integer!>!> getSupportedFrameRateRanges();
     method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
     method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
     method public boolean hasFlashUnit();
@@ -207,6 +208,7 @@
     method public int getImageQueueDepth();
     method public int getOutputImageFormat();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public boolean isOutputImageRotationEnabled();
     method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
@@ -234,9 +236,10 @@
     method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
     method public androidx.camera.core.ImageAnalysis.Builder setOutputImageFormat(int);
     method @RequiresApi(23) public androidx.camera.core.ImageAnalysis.Builder setOutputImageRotationEnabled(boolean);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
-    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
   }
 
@@ -245,6 +248,7 @@
     method public int getFlashMode();
     method @IntRange(from=1, to=100) public int getJpegQuality();
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method public void setCropAspectRatio(android.util.Rational);
     method public void setFlashMode(int);
@@ -271,9 +275,10 @@
     method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
     method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
     method public androidx.camera.core.ImageCapture.Builder setJpegQuality(@IntRange(from=1, to=100) int);
-    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
-    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
   }
 
@@ -379,6 +384,7 @@
 
   @RequiresApi(21) public final class Preview extends androidx.camera.core.UseCase {
     method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
@@ -388,9 +394,10 @@
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
     ctor public Preview.Builder();
     method public androidx.camera.core.Preview build();
-    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
     method public androidx.camera.core.Preview.Builder setTargetName(String);
-    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method @Deprecated public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
     method public androidx.camera.core.Preview.Builder setTargetRotation(int);
   }
 
@@ -510,3 +517,51 @@
 
 }
 
+package androidx.camera.core.resolutionselector {
+
+  @RequiresApi(21) public final class AspectRatioStrategy {
+    ctor public AspectRatioStrategy(int, int);
+    method public int getFallbackRule();
+    method public int getPreferredAspectRatio();
+    field public static final int FALLBACK_RULE_AUTO = 1; // 0x1
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY;
+    field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY;
+  }
+
+  @RequiresApi(21) public interface ResolutionFilter {
+    method public java.util.List<android.util.Size!> filter(java.util.List<android.util.Size!>, int);
+  }
+
+  @RequiresApi(21) public final class ResolutionSelector {
+    method public androidx.camera.core.resolutionselector.AspectRatioStrategy getAspectRatioStrategy();
+    method public int getHighResolutionEnabledFlag();
+    method public androidx.camera.core.resolutionselector.ResolutionFilter? getResolutionFilter();
+    method public androidx.camera.core.resolutionselector.ResolutionStrategy? getResolutionStrategy();
+    field public static final int HIGH_RESOLUTION_FLAG_OFF = 0; // 0x0
+    field public static final int HIGH_RESOLUTION_FLAG_ON = 1; // 0x1
+  }
+
+  public static final class ResolutionSelector.Builder {
+    ctor public ResolutionSelector.Builder();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector build();
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAspectRatioStrategy(androidx.camera.core.resolutionselector.AspectRatioStrategy);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setHighResolutionEnabledFlag(int);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter);
+    method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionStrategy(androidx.camera.core.resolutionselector.ResolutionStrategy);
+  }
+
+  @RequiresApi(21) public final class ResolutionStrategy {
+    ctor public ResolutionStrategy(android.util.Size, int);
+    method public android.util.Size? getBoundSize();
+    method public int getFallbackRule();
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER = 2; // 0x2
+    field public static final int FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER = 1; // 0x1
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER = 4; // 0x4
+    field public static final int FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER = 3; // 0x3
+    field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+    field public static final androidx.camera.core.resolutionselector.ResolutionStrategy HIGHEST_AVAILABLE_STRATEGY;
+  }
+
+}
+
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt
index 55f2c9f..2e24387 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt
@@ -74,10 +74,25 @@
     }
 
     @Test
-    fun expectedFrameRateIsNull_whenNotSet() {
+    fun expectedFrameRateIsUnspecified_whenNotSet() {
         val resolution = Size(640, 480)
         val request = createNewRequest(resolution)
-        Truth.assertThat(request.expectedFrameRate).isNull()
+        Truth.assertThat(request.expectedFrameRate).isEqualTo(
+            SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+        )
+    }
+
+    @Test
+    fun canRetrieveDynamicRange() {
+        val dynamicRange = DynamicRange.HDR_UNSPECIFIED_10_BIT
+        val request = createNewRequest(FAKE_SIZE, dynamicRange)
+        Truth.assertThat(request.dynamicRange).isEqualTo(dynamicRange)
+    }
+
+    @Test
+    fun dynamicRangeIsSdr_whenNotSet() {
+        val request = createNewRequest(FAKE_SIZE)
+        Truth.assertThat(request.dynamicRange).isEqualTo(DynamicRange.SDR)
     }
 
     @Test
@@ -371,11 +386,18 @@
 
     private fun createNewRequest(
         size: Size,
-        expectedFrameRate: Range<Int>? = null,
+        dynamicRange: DynamicRange = DynamicRange.SDR,
+        expectedFrameRate: Range<Int> = SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED,
         autoCleanup: Boolean = true,
         onInvalidated: () -> Unit = {},
     ): SurfaceRequest {
-        val request = SurfaceRequest(size, FakeCamera(), expectedFrameRate, onInvalidated)
+        val request = SurfaceRequest(
+            size,
+            FakeCamera(),
+            dynamicRange,
+            expectedFrameRate,
+            onInvalidated
+        )
         if (autoCleanup) {
             surfaceRequests.add(request)
         }
@@ -386,7 +408,8 @@
         private val FAKE_SIZE: Size by lazy { Size(0, 0) }
         private val FAKE_INFO: SurfaceRequest.TransformationInfo by lazy {
             SurfaceRequest.TransformationInfo.of(Rect(), 0, Surface.ROTATION_0,
-                /*hasCameraTransform=*/true)
+                /*hasCameraTransform=*/true
+            )
         }
         private val NO_OP_RESULT_LISTENER = Consumer { _: SurfaceRequest.Result? -> }
         private val MOCK_SURFACE = Mockito.mock(
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallback.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallback.kt
index 706d6ec..8aa7647 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallback.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/FakeTakePictureCallback.kt
@@ -34,7 +34,7 @@
     private var onDiskResultCont: Continuation<OutputFileResults>? = null
 
     override fun onImageCaptured() {
-        TODO("Not yet implemented")
+        TODO("onImageCaptured Not yet implemented")
     }
 
     override fun onFinalResult(outputFileResults: OutputFileResults) {
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
index c6c231e..3dfd2da 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
@@ -37,6 +37,7 @@
 import androidx.camera.core.internal.CameraCaptureResultImageInfo
 import androidx.camera.core.internal.utils.ImageUtil.jpegImageToJpegByteArray
 import androidx.camera.core.processing.InternalImageProcessor
+import androidx.camera.testing.AndroidUtil
 import androidx.camera.testing.ExifUtil
 import androidx.camera.testing.TestImageUtil.createBitmap
 import androidx.camera.testing.TestImageUtil.createJpegBytes
@@ -49,6 +50,8 @@
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.runBlocking
+import org.junit.Assume.assumeFalse
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -59,6 +62,12 @@
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = 21)
 class ProcessingNodeDeviceTest {
+
+    @Before
+    fun setUp() {
+        assumeFalse(AndroidUtil.isEmulatorAndAPI21())
+    }
+
     @Test
     fun applyBitmapEffectInMemory_effectApplied() = runBlocking {
         processJpegAndVerifyEffectApplied(null)
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
index 948437c..099b42b 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
@@ -19,11 +19,17 @@
 import android.graphics.SurfaceTexture
 import android.hardware.camera2.CameraDevice
 import android.opengl.Matrix
+import android.os.Build
 import android.os.Handler
 import android.os.HandlerThread
+import android.os.Looper
+import android.util.Size
 import android.view.Surface
+import androidx.annotation.RequiresApi
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.TestImageUtil.createBitmap
+import androidx.camera.testing.TestImageUtil.getAverageDiff
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
@@ -31,10 +37,12 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.Locale
 import kotlin.coroutines.ContinuationInterceptor
+import kotlin.coroutines.resume
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.android.asCoroutineDispatcher
 import kotlinx.coroutines.currentCoroutineContext
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import org.junit.After
 import org.junit.Before
@@ -127,6 +135,41 @@
         }
     }
 
+    @RequiresApi(Build.VERSION_CODES.M)
+    @Test
+    fun drawInputSurface_snapshotReturnsTheSame(): Unit = runBlocking(glDispatcher) {
+        // Arrange: set up renderer and Surface.
+        createOpenGlRendererAndInit()
+        val surfaceTexture = SurfaceTexture(glRenderer.textureName).apply {
+            setDefaultBufferSize(WIDTH, HEIGHT)
+            surfaceTexturesToRelease.add(this)
+        }
+        val inputSurface = Surface(surfaceTexture).apply {
+            surfacesToRelease.add(this)
+        }
+        // Create Bitmap for drawing
+        val inputImage = createBitmap(WIDTH, HEIGHT)
+        // Draw bitmap to inputSurface.
+        val canvas = inputSurface.lockHardwareCanvas()
+        canvas.drawBitmap(inputImage, 0f, 0f, null)
+        inputSurface.unlockCanvasAndPost(canvas)
+        // Wait for frame available and update texture.
+        suspendCancellableCoroutine { continuation ->
+            surfaceTexture.setOnFrameAvailableListener({
+                continuation.resume(Unit)
+            }, Handler(Looper.getMainLooper()))
+        }
+        surfaceTexture.updateTexImage()
+
+        // Act: take a snapshot.
+        val matrix = FloatArray(16)
+        Matrix.setIdentityM(matrix, 0)
+        val result = glRenderer.snapshot(Size(WIDTH, HEIGHT), matrix)
+
+        // Assert: the result is identical to the input.
+        assertThat(getAverageDiff(result, inputImage)).isEqualTo(0)
+    }
+
     @Test
     fun getTextureNameWithoutInit_throwException(): Unit = runBlocking(glDispatcher) {
         createOpenGlRenderer()
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 776138c..d6b1f62 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
@@ -17,6 +17,7 @@
 package androidx.camera.core;
 
 import android.graphics.ImageFormat;
+import android.util.Range;
 import android.view.Surface;
 
 import androidx.annotation.FloatRange;
@@ -32,6 +33,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * An interface for retrieving camera information.
@@ -268,6 +271,28 @@
     }
 
     /**
+     * Returns a list of the frame rate ranges, in frames per second, supported by this device's
+     * AE algorithm.
+     *
+     * <p>These are the frame rate ranges that the AE algorithm on the device can support. When
+     * CameraX is configured to run with the camera2 implementation, this list will be derived
+     * from {@link android.hardware.camera2.CameraCharacteristics
+     * #CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}, though ranges may be added or removed for
+     * compatibility reasons.
+     *
+     * <p>There is no guarantee that these ranges can be used for every size surface or
+     * combination of use cases. If attempting to run the device using an unsupported range, there
+     * may be stability issues or the device may quietly choose another frame rate operating range.
+     *
+     * @return The list of FPS ranges supported by the device's AE algorithm
+     * @see androidx.camera.video.VideoCapture.Builder#setTargetFrameRate(Range)
+     */
+    @NonNull
+    default List<Range<Integer>> getSupportedFrameRateRanges() {
+        return Collections.emptyList();
+    }
+
+    /**
      * Returns if {@link ImageFormat#PRIVATE} reprocessing is supported on the device.
      *
      * @return true if supported, otherwise false.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 573a0d7..c32f03c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -298,7 +298,7 @@
             ResolutionSelector.Builder resolutionSelectorBuilder =
                     ResolutionSelector.Builder.fromResolutionSelector(resolutionSelector);
             resolutionSelectorBuilder.setResolutionStrategy(
-                    ResolutionStrategy.create(analyzerResolution,
+                    new ResolutionStrategy(analyzerResolution,
                             ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER));
             builder.getMutableConfig().insertOption(OPTION_RESOLUTION_SELECTOR,
                     resolutionSelectorBuilder.build());
@@ -735,7 +735,6 @@
      * <p>This setting is set when constructing an ImageCapture using
      * {@link Builder#setResolutionSelector(ResolutionSelector)}.
      */
-    @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
     public ResolutionSelector getResolutionSelector() {
         return ((ImageOutputConfig) getCurrentConfig()).getResolutionSelector(null);
@@ -1008,7 +1007,7 @@
         private static final ResolutionSelector DEFAULT_RESOLUTION_SELECTOR =
                 new ResolutionSelector.Builder().setAspectRatioStrategy(
                         AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY).setResolutionStrategy(
-                        ResolutionStrategy.create(SizeUtil.RESOLUTION_VGA,
+                        new ResolutionStrategy(SizeUtil.RESOLUTION_VGA,
                                 ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER))
                         .build();
 
@@ -1289,6 +1288,8 @@
          *
          * @param aspectRatio The desired ImageAnalysis {@link AspectRatio}
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link AspectRatioStrategy} to specify
+         * the preferred aspect ratio settings instead.
          */
         @NonNull
         @Override
@@ -1392,6 +1393,8 @@
          *
          * @param resolution The target resolution to choose from supported output sizes list.
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link ResolutionStrategy} to specify
+         * the preferred resolution settings instead.
          */
         @NonNull
         @Override
@@ -1483,7 +1486,6 @@
          *
          * @return The current Builder.
          */
-        @RestrictTo(Scope.LIBRARY_GROUP)
         @Override
         @NonNull
         public Builder setResolutionSelector(@NonNull ResolutionSelector resolutionSelector) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index bdd3ddc..9126d7b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -933,7 +933,6 @@
      * <p>This setting is set when constructing an ImageCapture using
      * {@link Builder#setResolutionSelector(ResolutionSelector)}.
      */
-    @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
     public ResolutionSelector getResolutionSelector() {
         return ((ImageOutputConfig) getCurrentConfig()).getResolutionSelector(null);
@@ -2769,6 +2768,8 @@
          *
          * @param aspectRatio The desired ImageCapture {@link AspectRatio}
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link AspectRatioStrategy} to specify
+         * the preferred aspect ratio settings instead.
          */
         @NonNull
         @Override
@@ -2864,6 +2865,8 @@
          *
          * @param resolution The target resolution to choose from supported output sizes list.
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link ResolutionStrategy} to specify
+         * the preferred resolution settings instead.
          */
         @NonNull
         @Override
@@ -2912,7 +2915,6 @@
          *
          * @return The current Builder.
          */
-        @RestrictTo(Scope.LIBRARY_GROUP)
         @Override
         @NonNull
         public Builder setResolutionSelector(@NonNull ResolutionSelector resolutionSelector) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 816077f..ea180a3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -226,8 +226,12 @@
         // Close previous session's deferrable surface before creating new one
         clearPipeline();
 
-        final SurfaceRequest surfaceRequest = new SurfaceRequest(streamSpec.getResolution(),
-                getCamera(), this::notifyReset);
+        final SurfaceRequest surfaceRequest = new SurfaceRequest(
+                streamSpec.getResolution(),
+                getCamera(),
+                streamSpec.getDynamicRange(),
+                streamSpec.getExpectedFrameRateRange(),
+                this::notifyReset);
         mCurrentSurfaceRequest = surfaceRequest;
 
         if (mSurfaceProvider != null) {
@@ -558,7 +562,6 @@
      * <p>This setting is set when constructing an ImageCapture using
      * {@link Builder#setResolutionSelector(ResolutionSelector)}.
      */
-    @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
     public ResolutionSelector getResolutionSelector() {
         return ((ImageOutputConfig) getCurrentConfig()).getResolutionSelector(null);
@@ -931,6 +934,8 @@
          *
          * @param aspectRatio The desired Preview {@link AspectRatio}
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link AspectRatioStrategy} to specify
+         * the preferred aspect ratio settings instead.
          */
         @NonNull
         @Override
@@ -1029,6 +1034,8 @@
          *
          * @param resolution The target resolution to choose from supported output sizes list.
          * @return The current Builder.
+         * @deprecated use {@link ResolutionSelector} with {@link ResolutionStrategy} to specify
+         * the preferred resolution settings instead.
          */
         @NonNull
         @Override
@@ -1101,7 +1108,6 @@
          *
          * @return The current Builder.
          */
-        @RestrictTo(Scope.LIBRARY_GROUP)
         @Override
         @NonNull
         public Builder setResolutionSelector(@NonNull ResolutionSelector resolutionSelector) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
index f5d5a45..bc20e6b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
@@ -38,6 +38,7 @@
 import androidx.camera.core.impl.DeferrableSurface;
 import androidx.camera.core.impl.ImageFormatConstants;
 import androidx.camera.core.impl.ImageOutputConfig;
+import androidx.camera.core.impl.StreamSpec;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.FutureCallback;
 import androidx.camera.core.impl.utils.futures.Futures;
@@ -86,11 +87,23 @@
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public final class SurfaceRequest {
+
+    /**
+     * A frame rate range with no specified lower or upper bound.
+     *
+     * @see SurfaceRequest#getExpectedFrameRate()
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static final Range<Integer> FRAME_RATE_RANGE_UNSPECIFIED =
+            StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED;
+
     private final Object mLock = new Object();
 
     private final Size mResolution;
 
-    @Nullable
+    @NonNull
+    private final DynamicRange mDynamicRange;
+
     private final Range<Integer> mExpectedFrameRate;
     private final CameraInternal mCamera;
 
@@ -133,11 +146,11 @@
             @NonNull Size resolution,
             @NonNull CameraInternal camera,
             @NonNull Runnable onInvalidated) {
-        this(resolution, camera, /*expectedFrameRate=*/null, onInvalidated);
+        this(resolution, camera, DynamicRange.SDR, FRAME_RATE_RANGE_UNSPECIFIED, onInvalidated);
     }
 
     /**
-     * Creates a new surface request with the given resolution, {@link Camera}, and an optional
+     * Creates a new surface request with the given resolution, {@link Camera}, dynamic range, and
      * expected frame rate.
      *
      */
@@ -145,11 +158,13 @@
     public SurfaceRequest(
             @NonNull Size resolution,
             @NonNull CameraInternal camera,
-            @Nullable Range<Integer> expectedFrameRate,
+            @NonNull DynamicRange dynamicRange,
+            @NonNull Range<Integer> expectedFrameRate,
             @NonNull Runnable onInvalidated) {
         super();
         mResolution = resolution;
         mCamera = camera;
+        mDynamicRange = dynamicRange;
         mExpectedFrameRate = expectedFrameRate;
 
         // To ensure concurrency and ordering, operations are chained. Completion can only be
@@ -312,6 +327,23 @@
     }
 
     /**
+     * Returns the dynamic range expected to be used with the requested surface.
+     *
+     * <p>The dynamic range may have implications for which surface type is returned. Special
+     * care should be taken to ensure the provided surface can support the requested dynamic
+     * range. For example, if the returned dynamic range has {@link DynamicRange#getBitDepth()}
+     * equal to {@link DynamicRange#BIT_DEPTH_10_BIT}, then the surface provided to
+     * {@link #provideSurface(Surface, Executor, Consumer)} should use a format that can support
+     * ten bits of dynamic range, such as {@link android.graphics.ImageFormat#PRIVATE} or
+     * {@link android.graphics.ImageFormat#YCBCR_P010}.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @NonNull
+    public DynamicRange getDynamicRange() {
+        return mDynamicRange;
+    }
+
+    /**
      * Returns the expected rate at which frames will be produced into the provided {@link Surface}.
      *
      * <p>This information can be used to configure components that can be optimized by knowing
@@ -324,15 +356,15 @@
      * conditions. The frame rate may also be fixed, in which case {@link Range#getUpper()} will
      * be equivalent to {@link Range#getLower()}.
      *
-     * <p>This method may also return {@code null} if no information about the frame rate can be
-     * determined. In this case, no assumptions should be made about what the actual frame rate
-     * will be.
+     * <p>This method may also return {@link #FRAME_RATE_RANGE_UNSPECIFIED} if no information about
+     * the frame rate can be determined. In this case, no assumptions should be made about what
+     * the actual frame rate will be.
      *
-     * @return The expected frame rate range or {@code null} if no frame rate information is
-     * available.
+     * @return The expected frame rate range or {@link #FRAME_RATE_RANGE_UNSPECIFIED} if no frame
+     * rate information is available.
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @Nullable
+    @NonNull
     public Range<Integer> getExpectedFrameRate() {
         return mExpectedFrameRate;
     }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index e966604..adcb322 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -57,6 +57,7 @@
 import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.internal.TargetConfig;
 import androidx.camera.core.internal.utils.UseCaseConfigUtil;
+import androidx.camera.core.resolutionselector.ResolutionSelector;
 import androidx.camera.core.streamsharing.StreamSharing;
 import androidx.core.util.Preconditions;
 import androidx.lifecycle.LifecycleOwner;
@@ -262,8 +263,8 @@
         // Forces disable ZSL when high resolution is enabled.
         if (mergedConfig.containsOption(ImageOutputConfig.OPTION_RESOLUTION_SELECTOR)
                 && mergedConfig.retrieveOption(
-                ImageOutputConfig.OPTION_RESOLUTION_SELECTOR).getHighResolutionEnabledFlags()
-                != 0) {
+                ImageOutputConfig.OPTION_RESOLUTION_SELECTOR).getHighResolutionEnabledFlag()
+                != ResolutionSelector.HIGH_RESOLUTION_FLAG_OFF) {
             mergedConfig.insertOption(UseCaseConfig.OPTION_ZSL_DISABLED, true);
         }
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
index 9e6c442..cdde2a1 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/AttachedSurfaceInfo.java
@@ -22,6 +22,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
+import androidx.camera.core.DynamicRange;
 
 import com.google.auto.value.AutoValue;
 /**
@@ -43,8 +44,10 @@
     public static AttachedSurfaceInfo create(@NonNull SurfaceConfig surfaceConfig,
             int imageFormat,
             @NonNull Size size,
+            @NonNull DynamicRange dynamicRange,
             @Nullable Range<Integer> targetFrameRate) {
-        return new AutoValue_AttachedSurfaceInfo(surfaceConfig, imageFormat, size, targetFrameRate);
+        return new AutoValue_AttachedSurfaceInfo(surfaceConfig, imageFormat, size,
+                dynamicRange, targetFrameRate);
     }
 
     /** Returns the SurfaceConfig. */
@@ -58,6 +61,10 @@
     @NonNull
     public abstract Size getSize();
 
+    /** Returns the dynamic range of this surface. */
+    @NonNull
+    public abstract DynamicRange getDynamicRange();
+
     /** Returns the configuration target frame rate. */
     @Nullable
     public abstract Range<Integer> getTargetFrameRate();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
index 16ffabc..791efe0 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
@@ -18,7 +18,6 @@
 
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
-import android.util.Range;
 import android.util.Size;
 
 import androidx.annotation.NonNull;
@@ -68,17 +67,6 @@
     @NonNull
     Quirks getCameraQuirks();
 
-    /**
-     * Returns a list of the frame rate ranges supported by this device's AE algorithm.
-     *
-     * <p>These are the frame rate ranges that the AE algorithm on the device can support. There is
-     * no guarantee that these ranges will work for every size surface or combination of use cases.
-     *
-     * @return The list of frame rate ranges supported by the device's AE algorithm
-     */
-    @NonNull
-    List<Range<Integer>> getSupportedFrameRateRanges();
-
     /** Returns the {@link EncoderProfilesProvider} associated with this camera. */
     @NonNull
     EncoderProfilesProvider getEncoderProfilesProvider();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraMode.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraMode.java
index 322f141..18f09b9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraMode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraMode.java
@@ -17,6 +17,7 @@
 package androidx.camera.core.impl;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 import java.lang.annotation.Retention;
@@ -30,7 +31,6 @@
  *   <li> Default mode
  *   <li> Concurrent mode
  *   <li> Maximum resolution sensor pixel mode
- *   <li> HDR 10-bit mode
  * </ul>
  *
  * <p>The surface combination that is used depends on the camera mode. The defined constants are
@@ -56,6 +56,18 @@
     public @interface Mode {
     }
 
+    /**
+     * Returns a string representation of the CameraMode integer enum.
+     */
+    @NonNull
+    public static String toLabelString(@Mode int mode) {
+        switch (mode) {
+            case CONCURRENT_CAMERA: return "CONCURRENT_CAMERA";
+            case ULTRA_HIGH_RESOLUTION_CAMERA: return "ULTRA_HIGH_RESOLUTION_CAMERA";
+            default: return "DEFAULT";
+        }
+    }
+
     private CameraMode() {
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageInputConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageInputConfig.java
index 2947d4b..80703a7 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageInputConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageInputConfig.java
@@ -16,14 +16,19 @@
 
 package androidx.camera.core.impl;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.core.Camera;
+import androidx.camera.core.DynamicRange;
 
 /** Configuration containing options for configuring the input image data of a pipeline. */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public interface ImageInputConfig extends ReadableConfig {
     Config.Option<Integer> OPTION_INPUT_FORMAT =
             Config.Option.create("camerax.core.imageInput.inputFormat", int.class);
+    Config.Option<DynamicRange> OPTION_INPUT_DYNAMIC_RANGE =
+            Config.Option.create("camerax.core.imageInput.inputDynamicRange",
+                    DynamicRange.class);
 
     /**
      * Retrieve the input image format.
@@ -42,4 +47,16 @@
     default int getInputFormat() {
         return retrieveOption(OPTION_INPUT_FORMAT);
     }
+
+    /**
+     * Retrieve the required input {@link DynamicRange}.
+     *
+     * <p>This is the dynamic range that is required as input and it must be
+     * satisfied by the producer.
+     */
+    @Nullable
+    default DynamicRange getDynamicRange(@Nullable DynamicRange valueIfMissing) {
+        return retrieveOption(OPTION_INPUT_DYNAMIC_RANGE, valueIfMissing);
+    }
+
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/ResolutionSelectorUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/ResolutionSelectorUtil.java
index da7aaa3..fa50e17 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/ResolutionSelectorUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/ResolutionSelectorUtil.java
@@ -63,9 +63,10 @@
             builder.setResolutionFilter(resolutionSelectorToOverride.getResolutionFilter());
         }
 
-        if (resolutionSelectorToOverride.getHighResolutionEnabledFlags() != 0) {
-            builder.setHighResolutionEnabledFlags(
-                    resolutionSelectorToOverride.getHighResolutionEnabledFlags());
+        if (resolutionSelectorToOverride.getHighResolutionEnabledFlag()
+                != ResolutionSelector.HIGH_RESOLUTION_FLAG_OFF) {
+            builder.setHighResolutionEnabledFlag(
+                    resolutionSelectorToOverride.getHighResolutionEnabledFlag());
         }
 
         return builder.build();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index 7e4a9a5..9d3021c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -592,6 +592,7 @@
                             useCase.getAttachedSurfaceResolution());
             existingSurfaces.add(AttachedSurfaceInfo.create(surfaceConfig,
                     useCase.getImageFormat(), useCase.getAttachedSurfaceResolution(),
+                    Preconditions.checkNotNull(useCase.getAttachedStreamSpec()).getDynamicRange(),
                     useCase.getCurrentConfig().getTargetFrameRate(null)));
             suggestedStreamSpecs.put(useCase, useCase.getAttachedStreamSpec());
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorter.java
index 62baa3e..7b85044d 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorter.java
@@ -264,6 +264,11 @@
 
         Collections.sort(resolutionCandidateList, new CompareSizesByArea(true));
 
+        if (resolutionCandidateList.isEmpty()) {
+            Logger.w(TAG, "The retrieved supported resolutions from camera info internal is empty"
+                    + ". Format is " + imageFormat + ".");
+        }
+
         return resolutionCandidateList;
     }
 
@@ -284,7 +289,8 @@
     private List<Size> applyHighResolutionSettings(@NonNull List<Size> resolutionCandidateList,
             @NonNull ResolutionSelector resolutionSelector, int imageFormat) {
         // Appends high resolution output sizes if high resolution is enabled by ResolutionSelector
-        if (resolutionSelector.getHighResolutionEnabledFlags() != 0) {
+        if (resolutionSelector.getHighResolutionEnabledFlag()
+                == ResolutionSelector.HIGH_RESOLUTION_FLAG_ON) {
             List<Size> allSizesList = new ArrayList<>();
             allSizesList.addAll(resolutionCandidateList);
             allSizesList.addAll(mCameraInfoInternal.getSupportedHighResolutions(imageFormat));
@@ -397,7 +403,7 @@
         }
         Integer fallbackRule = resolutionStrategy.getFallbackRule();
 
-        if (fallbackRule == null) {
+        if (resolutionStrategy.equals(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY)) {
             // Do nothing for HIGHEST_AVAILABLE_STRATEGY case.
             return;
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacy.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacy.java
index 7483407..220ba0b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/SupportedOutputSizesSorterLegacy.java
@@ -123,7 +123,9 @@
         if (filteredSizeList.isEmpty()) {
             throw new IllegalArgumentException(
                     "All supported output sizes are filtered out according to current resolution "
-                            + "selection settings.");
+                            + "selection settings. \nminSize = "
+                            + minSize + "\nmaxSize = " + maxSize + "\ninitial size list: "
+                            + descendingSizeList);
         }
 
         Rational aspectRatio = getTargetAspectRatioByLegacyApi(imageOutputConfig, filteredSizeList);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
index 2479820..05fcd6f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
@@ -18,8 +18,12 @@
 
 import static android.opengl.GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
 
+import static androidx.camera.core.ImageProcessingUtil.copyByteBufferToBitmap;
+import static androidx.core.util.Preconditions.checkArgument;
+
 import static java.util.Objects.requireNonNull;
 
+import android.graphics.Bitmap;
 import android.opengl.EGL14;
 import android.opengl.EGLConfig;
 import android.opengl.EGLContext;
@@ -37,6 +41,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 import androidx.camera.core.Logger;
+import androidx.camera.core.SurfaceOutput;
 import androidx.core.util.Preconditions;
 
 import com.google.auto.value.AutoValue;
@@ -64,6 +69,7 @@
 
     private static final String VAR_TEXTURE_COORD = "vTextureCoord";
     private static final String VAR_TEXTURE = "sTexture";
+    private static final int PIXEL_STRIDE = 4;
 
     private static final String DEFAULT_VERTEX_SHADER = String.format(Locale.US,
             "uniform mat4 uTexMatrix;\n"
@@ -264,6 +270,132 @@
         }
     }
 
+    /**
+     * Takes a snapshot of the current external texture and returns a Bitmap.
+     *
+     * @param size             the size of the output {@link Bitmap}.
+     * @param textureTransform the transformation matrix.
+     *                         See: {@link SurfaceOutput#updateTransformMatrix(float[], float[])}
+     */
+    @NonNull
+    public Bitmap snapshot(@NonNull Size size, @NonNull float[] textureTransform) {
+        // Allocate buffer.
+        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(
+                size.getWidth() * size.getHeight() * PIXEL_STRIDE);
+        // Take a snapshot.
+        snapshot(byteBuffer, size, textureTransform);
+        // Create a Bitmap and copy the bytes over.
+        Bitmap bitmap = Bitmap.createBitmap(
+                size.getWidth(), size.getHeight(), Bitmap.Config.ARGB_8888);
+        byteBuffer.rewind();
+        copyByteBufferToBitmap(bitmap, byteBuffer, size.getWidth() * PIXEL_STRIDE);
+        return bitmap;
+    }
+
+    /**
+     * Takes a snapshot of the current external texture and stores it in the given byte buffer.
+     *
+     * <p> The image is stored as RGBA with pixel stride of 4 bytes and row stride of width * 4
+     * bytes.
+     *
+     * @param byteBuffer       the byte buffer to store the snapshot.
+     * @param size             the size of the output image.
+     * @param textureTransform the transformation matrix.
+     *                         See: {@link SurfaceOutput#updateTransformMatrix(float[], float[])}
+     */
+    private void snapshot(@NonNull ByteBuffer byteBuffer, @NonNull Size size,
+            @NonNull float[] textureTransform) {
+        checkArgument(byteBuffer.capacity() == size.getWidth() * size.getHeight() * 4,
+                "ByteBuffer capacity is not equal to width * height * 4.");
+        checkArgument(byteBuffer.isDirect(), "ByteBuffer is not direct.");
+
+        // Create and initialize intermediate texture.
+        int texture = generateTexture();
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
+        checkGlErrorOrThrow("glActiveTexture");
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
+        checkGlErrorOrThrow("glBindTexture");
+        // Configure the texture.
+        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, size.getWidth(),
+                size.getHeight(), 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null);
+        checkGlErrorOrThrow("glTexImage2D");
+        GLES20.glTexParameteri(
+                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameteri(
+                GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+
+        // Create FBO.
+        int fbo = generateFbo();
+        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);
+        checkGlErrorOrThrow("glBindFramebuffer");
+
+        // Attach the intermediate texture to the FBO
+        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
+                GLES20.GL_TEXTURE_2D, texture, 0);
+        checkGlErrorOrThrow("glFramebufferTexture2D");
+
+        // Bind external texture (camera output).
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        checkGlErrorOrThrow("glActiveTexture");
+        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTextureId);
+        checkGlErrorOrThrow("glBindTexture");
+
+        // Set scissor and viewport.
+        mCurrentSurface = null;
+        GLES20.glViewport(0, 0, size.getWidth(), size.getHeight());
+        GLES20.glScissor(0, 0, size.getWidth(), size.getHeight());
+
+        // Upload transform matrix.
+        GLES20.glUniformMatrix4fv(mTexMatrixLoc, /*count=*/1, /*transpose=*/false, textureTransform,
+                /*offset=*/0);
+        checkGlErrorOrThrow("glUniformMatrix4fv");
+
+        // Draw the external texture to the intermediate texture.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /*firstVertex=*/0, /*vertexCount=*/4);
+        checkGlErrorOrThrow("glDrawArrays");
+
+        // Read the pixels from the framebuffer
+        GLES20.glReadPixels(0, 0, size.getWidth(), size.getHeight(), GLES20.GL_RGBA,
+                GLES20.GL_UNSIGNED_BYTE,
+                byteBuffer);
+        checkGlErrorOrThrow("glReadPixels");
+
+        // Clean up
+        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+        deleteTexture(texture);
+        deleteFbo(fbo);
+        // Set the external texture to be active.
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTextureId);
+    }
+
+
+    private static int generateFbo() {
+        int[] fbos = new int[1];
+        GLES20.glGenFramebuffers(1, fbos, 0);
+        checkGlErrorOrThrow("glGenFramebuffers");
+        return fbos[0];
+    }
+
+    private static int generateTexture() {
+        int[] textures = new int[1];
+        GLES20.glGenTextures(1, textures, 0);
+        checkGlErrorOrThrow("glGenTextures");
+        return textures[0];
+    }
+
+    private static void deleteTexture(int texture) {
+        int[] textures = {texture};
+        GLES20.glDeleteTextures(1, textures, 0);
+        checkGlErrorOrThrow("glDeleteTextures");
+    }
+
+    private static void deleteFbo(int fbo) {
+        int[] fbos = {fbo};
+        GLES20.glDeleteFramebuffers(1, fbos, 0);
+        checkGlErrorOrThrow("glDeleteFramebuffers");
+    }
+
     private void createEglContext() {
         mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
         if (Objects.equals(mEglDisplay, EGL14.EGL_NO_DISPLAY)) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
index 77a1cc3..2344f84 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
@@ -31,7 +31,6 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Build;
-import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 import android.view.SurfaceView;
@@ -238,32 +237,14 @@
     @MainThread
     @NonNull
     public SurfaceRequest createSurfaceRequest(@NonNull CameraInternal cameraInternal) {
-        return createSurfaceRequest(cameraInternal, null);
-    }
-
-    /**
-     * Creates a {@link SurfaceRequest} that is linked to this {@link SurfaceEdge}.
-     *
-     * <p>The {@link SurfaceRequest} is for requesting a {@link Surface} from an external source
-     * such as {@code PreviewView} or {@code VideoCapture}. {@link SurfaceEdge} uses the
-     * {@link Surface} provided by {@link SurfaceRequest#provideSurface} as its source. For how
-     * the ref-counting works, please see the Javadoc of {@link #setProvider}.
-     *
-     * <p>It throws {@link IllegalStateException} if the current {@link SurfaceEdge}
-     * already has a provider.
-     *
-     * <p>This overload optionally allows allows specifying the expected frame rate range in which
-     * the surface should operate.
-     */
-    @MainThread
-    @NonNull
-    public SurfaceRequest createSurfaceRequest(@NonNull CameraInternal cameraInternal,
-            @Nullable Range<Integer> expectedFpsRange) {
         checkMainThread();
         checkNotClosed();
         // TODO(b/238230154) figure out how to support HDR.
-        SurfaceRequest surfaceRequest = new SurfaceRequest(mStreamSpec.getResolution(),
-                cameraInternal, expectedFpsRange,
+        SurfaceRequest surfaceRequest = new SurfaceRequest(
+                mStreamSpec.getResolution(),
+                cameraInternal,
+                mStreamSpec.getDynamicRange(),
+                mStreamSpec.getExpectedFrameRateRange(),
                 () -> mainThreadExecutor().execute(() -> {
                     if (!mIsClosed) {
                         invalidate();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
index 4fd50afd1..5f4ae6c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceProcessorNode.java
@@ -142,9 +142,9 @@
         Size rotatedCropSize = getRotatedSize(cropRect, rotationDegrees);
         checkArgument(isAspectRatioMatchingWithRoundingError(rotatedCropSize, outConfig.getSize()));
 
-        StreamSpec streamSpec = StreamSpec.builder(outConfig.getSize())
-                .setExpectedFrameRateRange(input.getStreamSpec().getExpectedFrameRateRange())
-                .build();
+        // Copy the stream spec from the input to the output, except for the resolution.
+        StreamSpec streamSpec = input.getStreamSpec().toBuilder().setResolution(
+                outConfig.getSize()).build();
 
         outputSurface = new SurfaceEdge(
                 outConfig.getTargets(),
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/AspectRatioStrategy.java b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/AspectRatioStrategy.java
index bf36dfde..4b88905 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/AspectRatioStrategy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/AspectRatioStrategy.java
@@ -16,6 +16,7 @@
 
 package androidx.camera.core.resolutionselector;
 
+import static androidx.camera.core.AspectRatio.RATIO_16_9;
 import static androidx.camera.core.AspectRatio.RATIO_4_3;
 
 import androidx.annotation.IntDef;
@@ -33,13 +34,20 @@
 /**
  * The aspect ratio strategy defines the sequence of aspect ratios that are used to select the
  * best size for a particular image.
+ *
+ * <p>Applications can create a {@link ResolutionSelector} with a proper AspectRatioStrategy to
+ * choose a resolution that matches the preferred aspect ratio.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public final class AspectRatioStrategy {
     /**
      * CameraX doesn't fall back to select sizes of any other aspect ratio when this fallback
      * rule is used.
+     *
+     * <p>Note that an AspectRatioStrategy with more restricted settings may result in that no
+     * resolution can be selected to use. Applications will receive
+     * {@link IllegalArgumentException} when binding the {@link UseCase}s with such kind of
+     * AspectRatioStrategy.
      */
     public static final int FALLBACK_RULE_NONE = 0;
     /**
@@ -70,38 +78,26 @@
      */
     @NonNull
     public static final AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY =
-            AspectRatioStrategy.create(RATIO_4_3, FALLBACK_RULE_AUTO);
+            new AspectRatioStrategy(RATIO_4_3, FALLBACK_RULE_AUTO);
+
+    /**
+     * The pre-defined aspect ratio strategy that selects sizes with
+     * {@link AspectRatio#RATIO_16_9} in priority. Then, selects sizes with other aspect ratios
+     * according to which aspect ratio can contain the closest FOV of the camera sensor.
+     *
+     * <p>Please see the
+     * <a href="https://source.android.com/docs/core/camera/camera3_crop_reprocess">Output streams,
+     * Cropping, and Zoom</a> introduction to know more about the camera FOV.
+     */
+    @NonNull
+    public static final AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY =
+            new AspectRatioStrategy(RATIO_16_9, FALLBACK_RULE_AUTO);
 
     @AspectRatio.Ratio
     private final int mPreferredAspectRatio;
     @AspectRatioFallbackRule
     private final int mFallbackRule;
 
-    private AspectRatioStrategy(@AspectRatio.Ratio int preferredAspectRatio,
-            @AspectRatioFallbackRule int fallbackRule) {
-        mPreferredAspectRatio = preferredAspectRatio;
-        mFallbackRule = fallbackRule;
-    }
-
-    /**
-     * Returns the specified preferred aspect ratio.
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @AspectRatio.Ratio
-    public int getPreferredAspectRatio() {
-        return mPreferredAspectRatio;
-    }
-
-    /**
-     * Returns the specified fallback rule for choosing the aspect ratio when the preferred aspect
-     * ratio is not available.
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @AspectRatioFallbackRule
-    public int getFallbackRule() {
-        return mFallbackRule;
-    }
-
     /**
      * Creates a new AspectRatioStrategy instance, configured with the specified preferred aspect
      * ratio and fallback rule.
@@ -123,10 +119,26 @@
      * @param preferredAspectRatio the preferred aspect ratio to select first.
      * @param fallbackRule the rule to follow when the preferred aspect ratio is not available.
      */
-    @NonNull
-    public static AspectRatioStrategy create(
-            @AspectRatio.Ratio int preferredAspectRatio,
+    public AspectRatioStrategy(@AspectRatio.Ratio int preferredAspectRatio,
             @AspectRatioFallbackRule int fallbackRule) {
-        return new AspectRatioStrategy(preferredAspectRatio, fallbackRule);
+        mPreferredAspectRatio = preferredAspectRatio;
+        mFallbackRule = fallbackRule;
+    }
+
+    /**
+     * Returns the specified preferred aspect ratio.
+     */
+    @AspectRatio.Ratio
+    public int getPreferredAspectRatio() {
+        return mPreferredAspectRatio;
+    }
+
+    /**
+     * Returns the specified fallback rule for choosing the aspect ratio when the preferred aspect
+     * ratio is not available.
+     */
+    @AspectRatioFallbackRule
+    public int getFallbackRule() {
+        return mFallbackRule;
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/HighResolution.java b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/HighResolution.java
deleted file mode 100644
index f9c0941..0000000
--- a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/HighResolution.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.core.resolutionselector;
-
-import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
-
-/**
- * The flags that are available in high resolution.
- */
-@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public final class HighResolution {
-    /**
-     * This flag enables high resolution in the default sensor pixel mode.
-     *
-     * <p>When using the <code>camera-camera2</code> CameraX implementation, please see
-     * {@link android.hardware.camera2.CaptureRequest#SENSOR_PIXEL_MODE} to know more information
-     * about the default and maximum resolution sensor pixel mode.
-     *
-     * <p>When this high resolution flag is set, the high resolution is retrieved via the
-     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
-     * from the stream configuration map obtained with the
-     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
-     * camera characteristics.
-     *
-     * <p>Since Android S, some devices might support a maximum resolution sensor pixel mode,
-     * which allows them to capture additional ultra high resolutions retrieved from
-     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION}
-     * . Enabling high resolution with this flag does not allow applications to select those
-     * ultra high resolutions.
-     */
-    public static final int FLAG_DEFAULT_MODE_ON = 0x1;
-
-    private HighResolution() {
-    }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionFilter.java b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionFilter.java
index 0756560..d3097c5 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionFilter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionFilter.java
@@ -17,12 +17,12 @@
 package androidx.camera.core.resolutionselector;
 
 import android.util.Size;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
 import androidx.camera.core.AspectRatio;
-import androidx.camera.core.ImageCapture;
+import androidx.camera.core.Preview;
 import androidx.camera.core.UseCase;
 
 import java.util.List;
@@ -31,9 +31,11 @@
  * Applications can filter out unsuitable sizes and sort the resolution list in the preferred
  * order by implementing the resolution filter interface. The preferred order is the order in
  * which the resolutions should be tried first.
+ *
+ * <p>Applications can create a {@link ResolutionSelector} with a proper ResolutionFilter to
+ * choose the preferred resolution.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public interface ResolutionFilter {
     /**
      * Removes unsuitable sizes and sorts the resolution list in the preferred order.
@@ -50,8 +52,12 @@
      * @param rotationDegrees the rotation degrees to rotate the image to the desired
      *                        orientation, matching the {@link UseCase}’s target rotation setting
      *                        . For example, the target rotation set via
-     *                        {@link ImageCapture.Builder#setTargetRotation(int)} or
-     *                        {@link ImageCapture#setTargetRotation(int)}.
+     *                        {@link Preview.Builder#setTargetRotation(int)} or
+     *                        {@link Preview#setTargetRotation(int)}. After rotating the sizes by
+     *                        the rotation degrees, applications can obtain the source image size
+     *                        in the specified target orientation. Then, applications can put the
+     *                        size that best fits to the {@link Preview}'s Android
+     *                        {@link View} size at the front of the returned list.
      * @return the desired ordered sizes list for resolution selection. The returned list should
      * only include sizes in the provided input supported sizes list.
      */
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionSelector.java b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionSelector.java
index 006cb53..3af804a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionSelector.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionSelector.java
@@ -18,19 +18,24 @@
 
 import static androidx.camera.core.resolutionselector.AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.camera.core.UseCase;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A set of requirements and priorities used to select a resolution for the {@link UseCase}.
  *
  * <p>The resolution selection mechanism is determined by the following three steps:
  * <ol>
  *     <li> Collect the supported output sizes and add them to the candidate resolution list.
- *     <li> Filter and sort the candidate resolution list according to the preference settings.
+ *     <li> Filter and sort the candidate resolution list according to the {@link Builder}
+ *     resolution settings.
  *     <li> Consider all the resolution selector settings of bound {@link UseCase}s to find the
  *     resolution that best suits each {@link UseCase}.
  * </ol>
@@ -41,7 +46,7 @@
  * <p>ResolutionSelector provides the following function for applications to adjust the candidate
  * resolution settings.
  * <ul>
- *     <li> {@link Builder#setHighResolutionEnabledFlags(int)}
+ *     <li> {@link Builder#setHighResolutionEnabledFlag(int)}
  * </ul>
  *
  * <p>For the second step, ResolutionSelector provides the following three functions for
@@ -76,36 +81,69 @@
  *
  * <p>When creating a ResolutionSelector instance, the
  * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be the default
- * {@link AspectRatioStrategy} if it is not set. However, if neither the
- * {@link ResolutionStrategy} nor the high resolution enabled flags are set, there will be no
- * default value specified.
+ * {@link AspectRatioStrategy} if it is not set.
+ * {@link ResolutionSelector#HIGH_RESOLUTION_FLAG_OFF} is the default value of high resolution
+ * enabled flag. However, if neither the {@link ResolutionStrategy} nor the
+ * {@link ResolutionFilter} are set, there will be no default value specified.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public final class ResolutionSelector {
-    @Nullable
+    /**
+     * This flag disables high resolution support.
+     */
+    public static final int HIGH_RESOLUTION_FLAG_OFF = 0;
+    /**
+     * This flag enables high resolution in the default sensor pixel mode.
+     *
+     * <p>This flag allows CameraX to select the highest resolution output sizes available on the
+     * camera device. The high resolution is retrieved via the
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
+     * from the stream configuration map obtained with the
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
+     * camera characteristics. However, please note that using a high resolution may result in
+     * slower capture times. Please see the javadoc of
+     * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
+     * for more details.
+     *
+     * <p>Since Android 12, some devices might support a maximum resolution sensor pixel mode,
+     * which allows them to capture additional ultra high resolutions retrieved from
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION}
+     * . Enabling high resolution with this flag does not allow applications to select those
+     * ultra high resolutions.
+     */
+    public static final int HIGH_RESOLUTION_FLAG_ON = 1;
+
+    @IntDef({HIGH_RESOLUTION_FLAG_OFF, HIGH_RESOLUTION_FLAG_ON})
+    @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public @interface HighResolutionFlag {
+    }
+    @NonNull
     private final AspectRatioStrategy mAspectRatioStrategy;
     @Nullable
     private final ResolutionStrategy mResolutionStrategy;
     @Nullable
     private final ResolutionFilter mResolutionFilter;
-    private final int mHighResolutionEnabledFlags;
+    @HighResolutionFlag
+    private final int mHighResolutionEnabledFlag;
 
     ResolutionSelector(
-            @Nullable AspectRatioStrategy aspectRatioStrategy,
+            @NonNull AspectRatioStrategy aspectRatioStrategy,
             @Nullable ResolutionStrategy resolutionStrategy,
             @Nullable ResolutionFilter resolutionFilter,
-            int highResolutionEnabledFlags) {
+            @HighResolutionFlag int highResolutionEnabledFlag) {
         mAspectRatioStrategy = aspectRatioStrategy;
         mResolutionStrategy = resolutionStrategy;
         mResolutionFilter = resolutionFilter;
-        mHighResolutionEnabledFlags = highResolutionEnabledFlags;
+        mHighResolutionEnabledFlag = highResolutionEnabledFlag;
     }
 
     /**
-     * Returns the specified {@link AspectRatioStrategy}, or null if not specified.
+     * Returns the specified {@link AspectRatioStrategy}, or
+     * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} if none is specified when
+     * creating the ResolutionSelector.
      */
-    @Nullable
+    @NonNull
     public AspectRatioStrategy getAspectRatioStrategy() {
         return mAspectRatioStrategy;
     }
@@ -127,10 +165,11 @@
     }
 
     /**
-     * Returns the specified high resolution enabled flags.
+     * Returns the specified high resolution enabled flag.
      */
-    public int getHighResolutionEnabledFlags() {
-        return mHighResolutionEnabledFlags;
+    @HighResolutionFlag
+    public int getHighResolutionEnabledFlag() {
+        return mHighResolutionEnabledFlag;
     }
 
     /**
@@ -143,7 +182,8 @@
         private ResolutionStrategy mResolutionStrategy = null;
         @Nullable
         private ResolutionFilter mResolutionFilter = null;
-        private int mHighResolutionEnabledFlags = 0;
+        @HighResolutionFlag
+        private int mHighResolutionEnabledFlag = HIGH_RESOLUTION_FLAG_OFF;
 
         /**
          * Creates a Builder instance.
@@ -155,7 +195,7 @@
             mAspectRatioStrategy = resolutionSelector.getAspectRatioStrategy();
             mResolutionStrategy = resolutionSelector.getResolutionStrategy();
             mResolutionFilter = resolutionSelector.getResolutionFilter();
-            mHighResolutionEnabledFlags = resolutionSelector.getHighResolutionEnabledFlags();
+            mHighResolutionEnabledFlag = resolutionSelector.getHighResolutionEnabledFlag();
         }
 
         /**
@@ -172,6 +212,9 @@
          * Sets the aspect ratio selection strategy for the {@link UseCase}. The aspect ratio
          * selection strategy determines how the {@link UseCase} will choose the aspect ratio of
          * the captured image.
+         *
+         * <p>If the aspect ratio strategy is not specified,
+         * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be used as the default.
          */
         @NonNull
         public Builder setAspectRatioStrategy(@NonNull AspectRatioStrategy aspectRatioStrategy) {
@@ -202,15 +245,16 @@
         }
 
         /**
-         * Sets high resolutions enabled flags to allow the application to select high
+         * Sets high resolutions enabled flag to allow the application to select high
          * resolutions for the {@link UseCase}s. This will enable the application to choose high
          * resolutions for the captured image, which may result in better quality images.
          *
-         * <p>Now, only {@link HighResolution#FLAG_DEFAULT_MODE_ON} is allowed for this function.
+         * <p>If not specified, the default setting is
+         * {@link ResolutionSelector#HIGH_RESOLUTION_FLAG_OFF}.
          */
         @NonNull
-        public Builder setHighResolutionEnabledFlags(int flags) {
-            mHighResolutionEnabledFlags = flags;
+        public Builder setHighResolutionEnabledFlag(@HighResolutionFlag int flag) {
+            mHighResolutionEnabledFlag = flag;
             return this;
         }
 
@@ -221,7 +265,7 @@
         @NonNull
         public ResolutionSelector build() {
             return new ResolutionSelector(mAspectRatioStrategy, mResolutionStrategy,
-                    mResolutionFilter, mHighResolutionEnabledFlags);
+                    mResolutionFilter, mHighResolutionEnabledFlag);
         }
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionStrategy.java b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionStrategy.java
index b0282e1..563d067 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionStrategy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/resolutionselector/ResolutionStrategy.java
@@ -32,9 +32,11 @@
 
 /**
  * The resolution strategy defines the resolution selection sequence to select the best size.
+ *
+ * <p>Applications can create a {@link ResolutionSelector} with a proper ResolutionStrategy to
+ * choose the preferred resolution.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public final class ResolutionStrategy {
     /**
      * A resolution strategy chooses the highest available resolution. This strategy does not
@@ -47,6 +49,10 @@
 
     /**
      * CameraX doesn't select an alternate size when the specified bound size is unavailable.
+     *
+     * <p>Applications will receive {@link IllegalArgumentException} when binding the
+     * {@link UseCase}s with this fallback rule if the device doesn't support the specified bound
+     * size.
      */
     public static final int FALLBACK_RULE_NONE = 0;
     /**
@@ -86,58 +92,14 @@
     public @interface ResolutionFallbackRule {
     }
 
-    private boolean mIsHighestAvailableStrategy = false;
     @Nullable
     private Size mBoundSize = null;
-    @Nullable
-    private Integer mFallbackRule = null;
+    private int mFallbackRule = ResolutionStrategy.FALLBACK_RULE_NONE;
 
     /**
      * Creates a default ResolutionStrategy instance to select the highest available resolution.
      */
     private ResolutionStrategy() {
-        mIsHighestAvailableStrategy = true;
-    }
-
-    /**
-     * Creates a ResolutionStrategy instance to select resolution according to the specified bound
-     * size and fallback rule.
-     */
-    private ResolutionStrategy(@NonNull Size boundSize,
-            @NonNull Integer fallbackRule) {
-        mBoundSize = boundSize;
-        mFallbackRule = fallbackRule;
-    }
-
-    /**
-     * Returns {@code true} if the instance is a highest available resolution strategy.
-     * Otherwise, returns {@code false}.
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public boolean isHighestAvailableStrategy() {
-        return mIsHighestAvailableStrategy;
-    }
-
-    /**
-     * Returns the specified bound size.
-     *
-     * @return the specified bound size or {@code null} if this is instance of
-     * {@link #HIGHEST_AVAILABLE_STRATEGY}.
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @Nullable
-    public Size getBoundSize() {
-        return mBoundSize;
-    }
-
-    /**
-     * Returns the fallback rule for choosing an alternate size when the specified bound size is
-     * unavailable.
-     */
-    @Nullable
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    public Integer getFallbackRule() {
-        return mFallbackRule;
     }
 
     /**
@@ -163,10 +125,28 @@
      * @param boundSize the bound size to select the best resolution with the fallback rule.
      * @param fallbackRule the rule to follow when the specified bound size is not available.
      */
-    @NonNull
-    public static ResolutionStrategy create(
-            @NonNull Size boundSize,
-            @ResolutionFallbackRule int fallbackRule) {
-        return new ResolutionStrategy(boundSize, fallbackRule);
+    public ResolutionStrategy(@NonNull Size boundSize, @ResolutionFallbackRule int fallbackRule) {
+        mBoundSize = boundSize;
+        mFallbackRule = fallbackRule;
+    }
+
+    /**
+     * Returns the specified bound size.
+     *
+     * @return the specified bound size or {@code null} if this is instance of
+     * {@link #HIGHEST_AVAILABLE_STRATEGY}.
+     */
+    @Nullable
+    public Size getBoundSize() {
+        return mBoundSize;
+    }
+
+    /**
+     * Returns the fallback rule for choosing an alternate size when the specified bound size is
+     * unavailable.
+     */
+    @ResolutionFallbackRule
+    public int getFallbackRule() {
+        return mFallbackRule;
     }
 }
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index a6289c1..682887e 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -224,6 +224,7 @@
         getMergedImageAnalysisConfig(null, null, -1, false).getTargetResolution();
     }
 
+    @SuppressWarnings("deprecation") // legacy resolution API
     @NonNull
     private ImageAnalysisConfig getMergedImageAnalysisConfig(
             @Nullable Size appResolution,
@@ -237,7 +238,7 @@
         if (useResolutionSelector) {
             ResolutionSelector.Builder selectorBuilder = new ResolutionSelector.Builder();
             if (appResolution != null) {
-                selectorBuilder.setResolutionStrategy(ResolutionStrategy.create(appResolution,
+                selectorBuilder.setResolutionStrategy(new ResolutionStrategy(appResolution,
                         ResolutionStrategy.FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER));
             } else {
                 selectorBuilder.setAspectRatioStrategy(
@@ -454,6 +455,7 @@
         assertCanReceiveAnalysisImage(mImageAnalysis);
     }
 
+    @SuppressWarnings("deprecation") // test for legacy resolution API
     @Test
     public void throwException_whenSetBothTargetResolutionAndAspectRatio() {
         assertThrows(IllegalArgumentException.class,
@@ -463,6 +465,7 @@
                         .build());
     }
 
+    @SuppressWarnings("deprecation") // test for legacy resolution API
     @Test
     public void throwException_whenSetTargetResolutionWithResolutionSelector() {
         assertThrows(IllegalArgumentException.class,
@@ -472,6 +475,7 @@
                         .build());
     }
 
+    @SuppressWarnings("deprecation") // test for legacy resolution API
     @Test
     public void throwException_whenSetTargetAspectRatioWithResolutionSelector() {
         assertThrows(IllegalArgumentException.class,
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
index f63384f..a7143fb 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
@@ -644,6 +644,7 @@
         assertThat(cameraControl.isZslConfigAdded).isTrue()
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetBothTargetResolutionAndAspectRatio() {
         assertThrows(IllegalArgumentException::class.java) {
@@ -652,6 +653,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetTargetResolutionWithResolutionSelector() {
         assertThrows(IllegalArgumentException::class.java) {
@@ -661,6 +663,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetTargetAspectRatioWithResolutionSelector() {
         assertThrows(IllegalArgumentException::class.java) {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index c504db0..fe701ff 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -203,6 +203,15 @@
     }
 
     @Test
+    fun surfaceRequestFrameRateRange_isUnspecified() {
+        // Target frame rate range isn't specified, so SurfaceRequest
+        // expected frame rate range should be unspecified.
+        assertThat(bindToLifecycleAndGetSurfaceRequest().expectedFrameRate).isEqualTo(
+            SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
+        )
+    }
+
+    @Test
     fun defaultMirrorModeIsOnFrontOnly() {
         val preview = Preview.Builder().build()
         assertThat(preview.mirrorModeInternal).isEqualTo(MIRROR_MODE_ON_FRONT_ONLY)
@@ -631,6 +640,7 @@
         assertThat(receivedAfterAttach).isTrue()
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetBothTargetResolutionAndAspectRatio() {
         Assert.assertThrows(IllegalArgumentException::class.java) {
@@ -639,6 +649,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetTargetResolutionWithResolutionSelector() {
         Assert.assertThrows(IllegalArgumentException::class.java) {
@@ -648,6 +659,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun throwException_whenSetTargetAspectRatioWithResolutionSelector() {
         Assert.assertThrows(IllegalArgumentException::class.java) {
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt
similarity index 88%
rename from camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt
rename to camera/camera-core/src/test/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt
index ad6ce08..cccbff0 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/JpegBytes2CroppedBitmapTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 import android.graphics.ImageFormat
 import android.graphics.Matrix
 import android.graphics.Rect
+import android.os.Build
 import android.util.Size
 import androidx.camera.core.imagecapture.Utils.CAMERA_CAPTURE_RESULT
 import androidx.camera.core.imagecapture.Utils.HEIGHT
@@ -29,19 +30,19 @@
 import androidx.camera.testing.ExifUtil.createExif
 import androidx.camera.testing.TestImageUtil.createJpegBytes
 import androidx.camera.testing.TestImageUtil.getAverageDiff
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
 
 /**
  * Unit tests for [JpegBytes2CroppedBitmap].
  */
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 21)
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 class JpegBytes2CroppedBitmapTest {
 
     private val operation = JpegBytes2CroppedBitmap()
@@ -68,8 +69,8 @@
         val output = operation.apply(input)
 
         // Assert: only the yellow and blue blocks exist after the cropping.
-        assertThat(getAverageDiff(output.data, Rect(0, 0, 320, 240), BLUE)).isEqualTo(0)
-        assertThat(getAverageDiff(output.data, Rect(321, 0, WIDTH, 240), YELLOW)).isEqualTo(0)
+        assertThat(getAverageDiff(output.data, Rect(0, 0, 320, 240), YELLOW)).isEqualTo(0)
+        assertThat(getAverageDiff(output.data, Rect(321, 0, WIDTH, 240), BLUE)).isEqualTo(0)
         // Assert: the packet info is correct.
         assertThat(output.cropRect).isEqualTo(Rect(0, 0, cropRect.width(), cropRect.height()))
         assertThat(output.exif).isEqualTo(input.exif)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/impl/AttachedSurfaceInfoTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/impl/AttachedSurfaceInfoTest.kt
index 8d36389..eab2744 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/impl/AttachedSurfaceInfoTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/impl/AttachedSurfaceInfoTest.kt
@@ -19,6 +19,7 @@
 import android.os.Build
 import android.util.Range
 import android.util.Size
+import androidx.camera.core.DynamicRange
 import com.google.common.truth.Truth
 import org.junit.Before
 import org.junit.Test
@@ -38,11 +39,12 @@
     )
     private val imageFormat = ImageFormat.JPEG
     private val size = Size(1920, 1080)
+    private val dynamicRange = DynamicRange.SDR
     private val targetFramerate = Range(10, 20)
     @Before
     fun setup() {
         attachedSurfaceInfo = AttachedSurfaceInfo.create(
-            surfaceConfig, imageFormat, size,
+            surfaceConfig, imageFormat, size, dynamicRange,
             targetFramerate
         )
     }
@@ -67,6 +69,11 @@
     }
 
     @Test
+    fun canGetDynamicRange() {
+        Truth.assertThat(attachedSurfaceInfo!!.dynamicRange).isEqualTo(dynamicRange)
+    }
+
+    @Test
     fun canGetTargetFrameRate() {
         Truth.assertThat(attachedSurfaceInfo!!.targetFrameRate).isEqualTo(targetFramerate)
     }
@@ -75,7 +82,10 @@
     fun nullGetTargetFrameRateReturnsNull() {
         val attachedSurfaceInfo2 = AttachedSurfaceInfo.create(
             surfaceConfig,
-            imageFormat, size, null
+            imageFormat,
+            size,
+            dynamicRange,
+            null
         )
         Truth.assertThat(attachedSurfaceInfo2.targetFrameRate).isNull()
     }
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
index ffbbada..0b1d574 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/SupportedOutputSizesSorterTest.kt
@@ -25,7 +25,6 @@
 import androidx.camera.core.impl.UseCaseConfigFactory.CaptureType
 import androidx.camera.core.impl.utils.AspectRatioUtil
 import androidx.camera.core.resolutionselector.AspectRatioStrategy
-import androidx.camera.core.resolutionselector.HighResolution
 import androidx.camera.core.resolutionselector.ResolutionFilter
 import androidx.camera.core.resolutionselector.ResolutionSelector
 import androidx.camera.core.resolutionselector.ResolutionStrategy
@@ -399,7 +398,7 @@
     fun getSupportedOutputSizes_whenHighResolutionIsEnabled_aspectRatio16x9() {
         verifySupportedOutputSizesWithResolutionSelectorSettings(
             preferredAspectRatio = AspectRatio.RATIO_16_9,
-            highResolutionEnabledFlags = HighResolution.FLAG_DEFAULT_MODE_ON,
+            highResolutionEnabledFlag = ResolutionSelector.HIGH_RESOLUTION_FLAG_ON,
             expectedList = listOf(
                 // Matched preferred AspectRatio items, sorted by area size.
                 Size(8000, 4500), // 16:9 high resolution size
@@ -427,7 +426,7 @@
     fun highResolutionCanNotBeSelected_whenHighResolutionForceDisabled() {
         verifySupportedOutputSizesWithResolutionSelectorSettings(
             preferredAspectRatio = AspectRatio.RATIO_16_9,
-            highResolutionEnabledFlags = HighResolution.FLAG_DEFAULT_MODE_ON,
+            highResolutionEnabledFlag = ResolutionSelector.HIGH_RESOLUTION_FLAG_ON,
             highResolutionForceDisabled = true,
             expectedList = listOf(
                 // Matched preferred AspectRatio items, sorted by area size.
@@ -546,7 +545,7 @@
         boundSize: Size? = null,
         resolutionFallbackRule: Int = FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER,
         resolutionFilter: ResolutionFilter? = null,
-        highResolutionEnabledFlags: Int = 0,
+        highResolutionEnabledFlag: Int = ResolutionSelector.HIGH_RESOLUTION_FLAG_OFF,
         highResolutionForceDisabled: Boolean = false,
         expectedList: List<Size> = Collections.emptyList(),
     ) {
@@ -558,7 +557,7 @@
             boundSize,
             resolutionFallbackRule,
             resolutionFilter,
-            highResolutionEnabledFlags,
+            highResolutionEnabledFlag,
             highResolutionForceDisabled
         )
         val resultList = outputSizesSorter.getSortedSupportedOutputSizes(useCaseConfig)
@@ -573,7 +572,7 @@
         boundSize: Size? = null,
         resolutionFallbackRule: Int = FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER,
         resolutionFilter: ResolutionFilter? = null,
-        highResolutionEnabledFlags: Int = 0,
+        highResolutionEnabledFlag: Int = ResolutionSelector.HIGH_RESOLUTION_FLAG_OFF,
         highResolutionForceDisabled: Boolean = false,
     ): UseCaseConfig<*> {
         val useCaseConfigBuilder = FakeUseCaseConfig.Builder(captureType, ImageFormat.JPEG)
@@ -581,7 +580,7 @@
 
         // Creates aspect ratio strategy and sets to resolution selector
         val aspectRatioStrategy = if (preferredAspectRatio != TARGET_ASPECT_RATIO_NONE) {
-            AspectRatioStrategy.create(preferredAspectRatio, aspectRatioFallbackRule)
+            AspectRatioStrategy(preferredAspectRatio, aspectRatioFallbackRule)
         } else {
             null
         }
@@ -594,7 +593,7 @@
         } else {
             boundSize?.let {
                 resolutionSelectorBuilder.setResolutionStrategy(
-                    ResolutionStrategy.create(
+                    ResolutionStrategy(
                         boundSize,
                         resolutionFallbackRule
                     )
@@ -605,7 +604,7 @@
         // Sets the resolution filter to resolution selector
         resolutionFilter?.let { resolutionSelectorBuilder.setResolutionFilter(it) }
         // Sets the high resolution enabled flags to resolution selector
-        resolutionSelectorBuilder.setHighResolutionEnabledFlags(highResolutionEnabledFlags)
+        resolutionSelectorBuilder.setHighResolutionEnabledFlag(highResolutionEnabledFlag)
 
         // Sets the custom resolution selector to use case config
         useCaseConfigBuilder.setResolutionSelector(resolutionSelectorBuilder.build())
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 0028e24..286acb9 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -421,14 +421,22 @@
      * {@link PackageManager#FEATURE_CAMERA_CONCURRENT} or cameras are already used by other
      * {@link UseCase}s, {@link UnsupportedOperationException} will be thrown.
      *
+     * <p>To set up concurrent camera, call {@link #getAvailableConcurrentCameraInfos()} to get
+     * the list of available combinations of concurrent cameras. Each sub-list contains the
+     * {@link CameraInfo}s for a combination of cameras that can be operated concurrently.
+     * Each camera can have its own {@link UseCase}s and {@link LifecycleOwner}. See
+     * <a href="{@docRoot}training/camerax/architecture#lifecycles">CameraX lifecycles</a>
+     *
      * @param singleCameraConfigs input list of {@link SingleCameraConfig}s.
      * @return output {@link ConcurrentCamera} instance.
      *
      * @throws IllegalArgumentException If less or more than two camera configs are provided.
      * @throws UnsupportedOperationException If device is not supporting concurrent camera or
      * cameras are already used by other {@link UseCase}s.
+     *
+     * @see ConcurrentCamera
+     * @see #getAvailableConcurrentCameraInfos()
      */
-    @SuppressWarnings({"lambdaLast"})
     @MainThread
     @NonNull
     public ConcurrentCamera bindToLifecycle(@NonNull List<SingleCameraConfig> singleCameraConfigs) {
diff --git a/camera/camera-testing/src/androidTest/java/androidx/camera/testing/TestImageUtilDeviceTest.kt b/camera/camera-testing/src/androidTest/java/androidx/camera/testing/TestImageUtilDeviceTest.kt
index a84ed46..1045e0b 100644
--- a/camera/camera-testing/src/androidTest/java/androidx/camera/testing/TestImageUtilDeviceTest.kt
+++ b/camera/camera-testing/src/androidTest/java/androidx/camera/testing/TestImageUtilDeviceTest.kt
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 package androidx.camera.testing
-
 import android.graphics.BitmapFactory.decodeByteArray
 import android.graphics.Color.BLUE
 import android.graphics.Color.GREEN
@@ -22,7 +21,6 @@
 import android.graphics.Color.YELLOW
 import android.graphics.Rect
 import androidx.camera.core.internal.utils.ImageUtil.jpegImageToJpegByteArray
-import androidx.camera.testing.TestImageUtil.calculateColorDiff
 import androidx.camera.testing.TestImageUtil.createJpegBytes
 import androidx.camera.testing.TestImageUtil.createJpegFakeImageProxy
 import androidx.camera.testing.TestImageUtil.getAverageDiff
@@ -32,7 +30,6 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
-
 /**
  * Unit tests for [TestImageUtil]
  */
@@ -48,12 +45,6 @@
     }
 
     @Test
-    fun testColorDiff() {
-        assertThat(calculateColorDiff(RED, RED)).isEqualTo(0)
-        assertThat(calculateColorDiff(RED, BLUE)).isEqualTo(255 * 2 / 3)
-    }
-
-    @Test
     fun createTestJpeg_verifyColor() {
         // Act.
         val jpegBytes = createJpegBytes(WIDTH, HEIGHT)
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/TestImageUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/TestImageUtil.java
index 933bc2c..b04224a 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/TestImageUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/TestImageUtil.java
@@ -32,7 +32,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
-import androidx.annotation.VisibleForTesting;
 import androidx.camera.core.ImageInfo;
 import androidx.camera.core.internal.CameraCaptureResultImageInfo;
 import androidx.camera.testing.fakes.FakeCameraCaptureResult;
@@ -174,11 +173,10 @@
      * <p>The difference is calculated as the average difference of each R, G and B color
      * components.
      */
-    @VisibleForTesting
-    static int calculateColorDiff(int color1, int color2) {
+    private static int calculateColorDiff(int color1, int color2) {
         int diff = 0;
         for (int shift = 0; shift <= 16; shift += 8) {
-            diff += Math.abs(((color1 >> shift) & 0xFF) - ((color2 >> shift) & 0xFF));
+            diff += Math.abs((color1 >> shift) & 0xFF - (color2 >> shift) & 0xFF);
         }
         return diff / 3;
     }
diff --git a/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java b/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
index 6d549cf..aafc3572 100644
--- a/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
+++ b/camera/camera-testing/src/test/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManagerTest.java
@@ -31,6 +31,7 @@
 import android.util.Size;
 
 import androidx.annotation.NonNull;
+import androidx.camera.core.DynamicRange;
 import androidx.camera.core.ImageAnalysis;
 import androidx.camera.core.impl.AttachedSurfaceInfo;
 import androidx.camera.core.impl.CameraMode;
@@ -103,6 +104,7 @@
                         SurfaceConfig.create(YUV, PREVIEW),
                         YUV_420_888,
                         new Size(1, 1),
+                        DynamicRange.SDR,
                         new Range<>(30, 30));
         mFakeCameraDeviceSurfaceManager.getSuggestedStreamSpecs(
                 CameraMode.DEFAULT,
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
index 3815854..1b0eb61 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
@@ -218,6 +218,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     private suspend fun runRecordingRoutineAndReturnNumDroppedFrames(): Int = coroutineScope {
         cameraProvider = ProcessCameraProvider.getInstance(context).await()
         needsShutdown = true
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
index afdaa23..354f38a 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolverTest.kt
@@ -17,6 +17,7 @@
 package androidx.camera.video.internal.config
 
 import android.util.Range
+import androidx.camera.core.SurfaceRequest
 import androidx.camera.core.impl.Timebase
 import androidx.camera.testing.EncoderProfilesUtil
 import androidx.camera.video.VideoSpec
@@ -37,11 +38,11 @@
         val TIMEBASE = Timebase.UPTIME
         const val FRAME_RATE_30 = 30
         const val FRAME_RATE_45 = 45
-        const val FRAME_RATE_60 = 60
+        val DEFAULT_VIDEO_SPEC: VideoSpec by lazy {
+            VideoSpec.builder().build()
+        }
     }
 
-    private val defaultVideoSpec = VideoSpec.builder().build()
-
     @Test
     fun defaultVideoSpecProducesValidSettings_forDifferentSurfaceSizes() {
         val surfaceSizeCif = EncoderProfilesUtil.RESOLUTION_CIF
@@ -54,7 +55,7 @@
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                defaultVideoSpec,
+                DEFAULT_VIDEO_SPEC,
                 surfaceSizeCif,
                 expectedFrameRateRange
             )
@@ -62,7 +63,7 @@
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                defaultVideoSpec,
+                DEFAULT_VIDEO_SPEC,
                 surfaceSize720p,
                 expectedFrameRateRange
             )
@@ -70,7 +71,7 @@
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                defaultVideoSpec,
+                DEFAULT_VIDEO_SPEC,
                 surfaceSize1080p,
                 expectedFrameRateRange
             )
@@ -103,9 +104,9 @@
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                defaultVideoSpec,
+                DEFAULT_VIDEO_SPEC,
                 surfaceSize720p,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get()
         val defaultBitrate = defaultConfig.bitrate
 
@@ -124,7 +125,7 @@
                 TIMEBASE,
                 higherVideoSpec,
                 surfaceSize720p,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isEqualTo(higherBitrate)
 
@@ -134,74 +135,45 @@
                 TIMEBASE,
                 lowerVideoSpec,
                 surfaceSize720p,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isEqualTo(lowerBitrate)
     }
 
     @Test
-    fun frameRateIsChosenFromVideoSpec_whenNoExpectedRangeProvided() {
-        // Give a VideoSpec with a frame rate higher than 30
-        val videoSpec =
-            VideoSpec.builder().setFrameRate(Range(FRAME_RATE_60, FRAME_RATE_60)).build()
+    fun frameRateIsDefault_whenNoExpectedRangeProvided() {
         val size = EncoderProfilesUtil.RESOLUTION_1080P
 
         assertThat(
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                videoSpec,
+                DEFAULT_VIDEO_SPEC,
                 size,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().frameRate
         ).isEqualTo(
-            FRAME_RATE_60
+            VideoEncoderConfigDefaultResolver.VIDEO_FRAME_RATE_FIXED_DEFAULT
         )
     }
 
     @Test
-    fun frameRateIsChosenFromExpectedRange_whenNoOverlapWithVideoSpec() {
-        // Give a VideoSpec with a frame rate higher than 30
-        val videoSpec =
-            VideoSpec.builder().setFrameRate(Range(FRAME_RATE_60, FRAME_RATE_60)).build()
+    fun frameRateIsChosenFromUpperOfExpectedRange_whenProvided() {
         val size = EncoderProfilesUtil.RESOLUTION_1080P
 
-        val expectedFrameRateRange = Range(FRAME_RATE_30, FRAME_RATE_30)
+        val expectedFrameRateRange = Range(FRAME_RATE_30, FRAME_RATE_45)
 
         // Expected frame rate range takes precedence over VideoSpec
         assertThat(
             VideoEncoderConfigDefaultResolver(
                 MIME_TYPE,
                 TIMEBASE,
-                videoSpec,
+                DEFAULT_VIDEO_SPEC,
                 size,
                 expectedFrameRateRange
             ).get().frameRate
         ).isEqualTo(
-            FRAME_RATE_30
+            FRAME_RATE_45
         )
     }
-
-    @Test
-    fun frameRateIsChosenFromOverlapOfExpectedRangeAndVideoSpec() {
-        // Give a VideoSpec with a frame rate higher than 30
-        val videoSpec =
-            VideoSpec.builder().setFrameRate(Range(FRAME_RATE_30, FRAME_RATE_45)).build()
-        val size = EncoderProfilesUtil.RESOLUTION_1080P
-
-        val expectedFrameRateRange = Range(FRAME_RATE_30, FRAME_RATE_60)
-
-        val intersection = expectedFrameRateRange.intersect(videoSpec.frameRate)
-
-        // Expected frame rate range takes precedence over VideoSpec
-        assertThat(
-            VideoEncoderConfigDefaultResolver(
-                MIME_TYPE,
-                TIMEBASE,
-                videoSpec,
-                size,
-                expectedFrameRateRange
-            ).get().frameRate
-        ).isIn(com.google.common.collect.Range.closed(intersection.lower, intersection.upper))
-    }
 }
\ No newline at end of file
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
index 42ff63b..2ebc49b 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolverTest.kt
@@ -23,6 +23,7 @@
 import androidx.camera.camera2.pipe.integration.CameraPipeConfig
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.CameraXConfig
+import androidx.camera.core.SurfaceRequest
 import androidx.camera.core.impl.Timebase
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.CameraPipeConfigTestRule
@@ -114,7 +115,7 @@
                 defaultVideoSpec,
                 Size(videoProfile.width, videoProfile.height),
                 videoProfile,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get()
 
             assertThat(config.mimeType).isEqualTo(videoProfile.mediaType)
@@ -135,7 +136,7 @@
             defaultVideoSpec,
             surfaceSize,
             profile,
-            /*expectedFrameRateRange=*/null
+            SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
         ).get().bitrate
 
         val increasedSurfaceSize = Size(surfaceSize.width + 100, surfaceSize.height + 100)
@@ -148,7 +149,7 @@
                 defaultVideoSpec,
                 increasedSurfaceSize,
                 profile,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isGreaterThan(defaultBitrate)
 
@@ -159,7 +160,7 @@
                 defaultVideoSpec,
                 decreasedSurfaceSize,
                 profile,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isLessThan(defaultBitrate)
     }
@@ -175,7 +176,7 @@
             defaultVideoSpec,
             surfaceSize,
             profile,
-            /*expectedFrameRateRange=*/null
+            SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
         ).get().bitrate
 
         // Create video spec with limit 20% higher than default.
@@ -194,7 +195,7 @@
                 higherVideoSpec,
                 surfaceSize,
                 profile,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isEqualTo(higherBitrate)
 
@@ -205,7 +206,7 @@
                 lowerVideoSpec,
                 surfaceSize,
                 profile,
-                /*expectedFrameRateRange=*/null
+                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
             ).get().bitrate
         ).isEqualTo(lowerBitrate)
     }
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
index 1369ac2..04d5d9b 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
@@ -25,6 +25,7 @@
 import androidx.camera.core.Camera
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.CameraXConfig
+import androidx.camera.core.SurfaceRequest
 import androidx.camera.core.impl.CameraInfoInternal
 import androidx.camera.core.impl.Timebase
 import androidx.camera.testing.CameraPipeConfigTestRule
@@ -165,7 +166,7 @@
             videoSpec,
             resolution!!,
             videoProfile,
-            /*expectedFrameRateRange=*/null
+            SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
         ).get().toMediaFormat()
 
         // Act.
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index 007e45d..576c0ff 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -132,6 +132,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CancellationException;
@@ -569,16 +570,19 @@
         // handleInvalidate() can be used as an alternative.
         Runnable onSurfaceInvalidated = this::notifyReset;
 
-        // TODO(b/229410005): The expected FPS range will need to come from the camera rather
-        //  than what is requested in the config. For now we use the default range of (30, 30)
-        //  for behavioral consistency.
-        Range<Integer> targetFpsRange = requireNonNull(
-                config.getTargetFrameRate(Defaults.DEFAULT_FPS_RANGE));
+        // If the expected frame rate range is unspecified, we need to give an educated estimate
+        // on what frame rate the camera will be operating at. For most devices this is a
+        // constant frame rate of 30fps, but in the future this could probably be queried from
+        // the camera.
+        Range<Integer> expectedFrameRate = streamSpec.getExpectedFrameRateRange();
+        if (Objects.equals(expectedFrameRate, StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED)) {
+            expectedFrameRate = Defaults.DEFAULT_FPS_RANGE;
+        }
         MediaSpec mediaSpec = requireNonNull(getMediaSpec());
         LegacyVideoCapabilities videoCapabilities = LegacyVideoCapabilities.from(
                 camera.getCameraInfo());
         VideoEncoderInfo videoEncoderInfo = getVideoEncoderInfo(config.getVideoEncoderInfoFinder(),
-                videoCapabilities, mediaSpec, resolution, targetFpsRange);
+                videoCapabilities, mediaSpec, resolution, expectedFrameRate);
         mCropRect = calculateCropRect(resolution, videoEncoderInfo);
         mNode = createNodeIfNeeded(camera, mCropRect, resolution);
         // Choose Timebase based on the whether the buffer is copied.
@@ -596,10 +600,13 @@
         if (mNode != null) {
             // Make sure the previously created camera edge is cleared before creating a new one.
             checkState(mCameraEdge == null);
+            // Update the StreamSpec to use the frame rate range that is not unspecified.
+            StreamSpec updatedStreamSpec =
+                    streamSpec.toBuilder().setExpectedFrameRateRange(expectedFrameRate).build();
             SurfaceEdge cameraEdge = new SurfaceEdge(
                     VIDEO_CAPTURE,
                     INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
-                    streamSpec,
+                    updatedStreamSpec,
                     getSensorToBufferTransformMatrix(),
                     camera.getHasTransform(),
                     mCropRect,
@@ -616,7 +623,7 @@
             SurfaceEdge appEdge = requireNonNull(nodeOutput.get(outConfig));
             appEdge.addOnInvalidatedListener(
                     () -> onAppEdgeInvalidated(appEdge, camera, config, timebase));
-            mSurfaceRequest = appEdge.createSurfaceRequest(camera, targetFpsRange);
+            mSurfaceRequest = appEdge.createSurfaceRequest(camera);
             mDeferrableSurface = cameraEdge.getDeferrableSurface();
             DeferrableSurface latestDeferrableSurface = mDeferrableSurface;
             mDeferrableSurface.getTerminationFuture().addListener(() -> {
@@ -627,7 +634,11 @@
                 }
             }, CameraXExecutors.mainThreadExecutor());
         } else {
-            mSurfaceRequest = new SurfaceRequest(resolution, camera, targetFpsRange,
+            mSurfaceRequest = new SurfaceRequest(
+                    resolution,
+                    camera,
+                    streamSpec.getDynamicRange(),
+                    expectedFrameRate,
                     onSurfaceInvalidated);
             mDeferrableSurface = mSurfaceRequest.getDeferrableSurface();
         }
@@ -640,6 +651,8 @@
 
         SessionConfig.Builder sessionConfigBuilder = SessionConfig.Builder.createFrom(config,
                 streamSpec.getResolution());
+        // Use the frame rate range directly from the StreamSpec here (don't resolve it to the
+        // default if unresolved).
         sessionConfigBuilder.setExpectedFrameRateRange(streamSpec.getExpectedFrameRateRange());
         sessionConfigBuilder.addErrorListener(
                 (sessionConfig, error) -> resetPipeline(cameraId, config, streamSpec));
@@ -1027,7 +1040,7 @@
             @NonNull LegacyVideoCapabilities videoCapabilities,
             @NonNull MediaSpec mediaSpec,
             @NonNull Size resolution,
-            @NonNull Range<Integer> targetFps) {
+            @NonNull Range<Integer> expectedFrameRate) {
         if (mVideoEncoderInfo != null) {
             return mVideoEncoderInfo;
         }
@@ -1036,7 +1049,7 @@
         VideoValidatedEncoderProfilesProxy encoderProfiles =
                 videoCapabilities.findHighestSupportedEncoderProfilesFor(resolution);
         VideoEncoderInfo videoEncoderInfo = resolveVideoEncoderInfo(videoEncoderInfoFinder,
-                encoderProfiles, mediaSpec, resolution, targetFps);
+                encoderProfiles, mediaSpec, resolution, expectedFrameRate);
         if (videoEncoderInfo == null) {
             // If VideoCapture cannot find videoEncoderInfo, it means that VideoOutput should
             // also not be able to find the encoder. VideoCapture will not handle this situation
@@ -1064,7 +1077,7 @@
             @Nullable VideoValidatedEncoderProfilesProxy encoderProfiles,
             @NonNull MediaSpec mediaSpec,
             @NonNull Size resolution,
-            @NonNull Range<Integer> targetFps) {
+            @NonNull Range<Integer> expectedFrameRate) {
         // Resolve the VideoEncoderConfig
         MimeInfo videoMimeInfo = resolveVideoMimeInfo(mediaSpec, encoderProfiles);
         VideoEncoderConfig videoEncoderConfig = resolveVideoEncoderConfig(
@@ -1073,7 +1086,7 @@
                 Timebase.UPTIME,
                 mediaSpec.getVideoSpec(),
                 resolution,
-                targetFps);
+                expectedFrameRate);
 
         return videoEncoderInfoFinder.apply(videoEncoderConfig);
     }
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
index 5859263..507f856 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoRecordEvent.java
@@ -417,6 +417,7 @@
                 case ERROR_RECORDER_ERROR: return "ERROR_RECORDER_ERROR";
                 case ERROR_NO_VALID_DATA: return "ERROR_NO_VALID_DATA";
                 case ERROR_SOURCE_INACTIVE: return "ERROR_SOURCE_INACTIVE";
+                case ERROR_DURATION_LIMIT_REACHED: return "ERROR_DURATION_LIMIT_REACHED";
             }
 
             // Should never reach here, but just in case...
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
index 8d3be191..5393edc 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoConfigUtil.java
@@ -106,13 +106,13 @@
      * @param videoSpec              the video spec.
      * @param inputTimebase          the timebase of the input frame.
      * @param surfaceSize            the surface size.
-     * @param expectedFrameRateRange the expected frame rate range. It could be null.
+     * @param expectedFrameRateRange the expected frame rate range.
      * @return a VideoEncoderConfig.
      */
     @NonNull
     public static VideoEncoderConfig resolveVideoEncoderConfig(@NonNull MimeInfo videoMimeInfo,
             @NonNull Timebase inputTimebase, @NonNull VideoSpec videoSpec,
-            @NonNull Size surfaceSize, @Nullable Range<Integer> expectedFrameRateRange) {
+            @NonNull Size surfaceSize, @NonNull Range<Integer> expectedFrameRateRange) {
         Supplier<VideoEncoderConfig> configSupplier;
         VideoValidatedEncoderProfilesProxy profiles = videoMimeInfo.getCompatibleEncoderProfiles();
         if (profiles != null) {
@@ -127,37 +127,6 @@
         return configSupplier.get();
     }
 
-    static int resolveFrameRate(@NonNull Range<Integer> preferredRange,
-            int exactFrameRateHint, @Nullable Range<Integer> strictOperatingFpsRange) {
-        Range<Integer> refinedRange;
-        if (strictOperatingFpsRange != null) {
-            // We have a strict operating range. Our frame rate should always be in this
-            // range. Since we can only choose a single frame rate (which acts as a target for
-            // VBR), we can only fine tune our preferences within that range.
-            try {
-                // First, let's try to intersect with the preferred frame rate range since this
-                // could contain intent from the user.
-                refinedRange = strictOperatingFpsRange.intersect(preferredRange);
-            } catch (IllegalArgumentException ex) {
-                // Ranges are disjoint. Choose the closest extreme as our frame rate.
-                if (preferredRange.getUpper() < strictOperatingFpsRange.getLower()) {
-                    // Preferred range is below operating range.
-                    return strictOperatingFpsRange.getLower();
-                } else {
-                    // Preferred range is above operating range.
-                    return strictOperatingFpsRange.getUpper();
-                }
-            }
-        } else {
-            // We only have the preferred range as a hint since the operating range is null.
-            refinedRange = preferredRange;
-        }
-
-        // Finally, try to apply the exact frame rate hint to the refined range since
-        // other settings may expect this number.
-        return refinedRange.clamp(exactFrameRateHint);
-    }
-
     static int scaleAndClampBitrate(
             int baseBitrate,
             int actualFrameRate, int baseFrameRate,
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
index 75d159f..7d09ed2 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigDefaultResolver.java
@@ -20,14 +20,16 @@
 import android.util.Size;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.core.Logger;
+import androidx.camera.core.SurfaceRequest;
 import androidx.camera.core.impl.Timebase;
 import androidx.camera.video.VideoSpec;
 import androidx.camera.video.internal.encoder.VideoEncoderConfig;
 import androidx.core.util.Supplier;
 
+import java.util.Objects;
+
 /**
  * A {@link VideoEncoderConfig} supplier that resolves requested encoder settings from a
  * {@link VideoSpec} for the given surface {@link Size} using pre-defined default values.
@@ -42,7 +44,7 @@
     private static final int VIDEO_BITRATE_BASE = 14000000;
     private static final Size VIDEO_SIZE_BASE = new Size(1280, 720);
     private static final int VIDEO_FRAME_RATE_BASE = 30;
-    private static final int VIDEO_FRAME_RATE_FIXED_DEFAULT = 30;
+    static final int VIDEO_FRAME_RATE_FIXED_DEFAULT = 30;
     private static final Range<Integer> VALID_FRAME_RATE_RANGE = new Range<>(1, 60);
 
     private final String mMimeType;
@@ -50,21 +52,28 @@
     private final Timebase mInputTimebase;
     private final VideoSpec mVideoSpec;
     private final Size mSurfaceSize;
-    @Nullable
     private final Range<Integer> mExpectedFrameRateRange;
 
     /**
      * Constructor for a VideoEncoderConfigDefaultResolver.
      *
-     * @param mimeType      The mime type for the video encoder
-     * @param inputTimebase The time base of the input frame.
-     * @param videoSpec     The {@link VideoSpec} which defines the settings that should be used
-     *                      with the video encoder.
-     * @param surfaceSize   The size of the surface required by the camera for the video encoder.
+     * @param mimeType               The mime type for the video encoder
+     * @param inputTimebase          The time base of the input frame.
+     * @param videoSpec              The {@link VideoSpec} which defines the settings that should
+     *                               be used with the video encoder.
+     * @param surfaceSize            The size of the surface required by the camera for the video
+     *                               encoder.
+     * @param expectedFrameRateRange The expected source frame rate range. This should act as an
+     *                               envelope for any frame rate calculated from {@code videoSpec
+     *                               } and {@code videoProfile} since the source should not
+     *                               produce frames at a frame rate outside this range. If
+     *                               equal to {@link SurfaceRequest#FRAME_RATE_RANGE_UNSPECIFIED},
+     *                               then no information about the source frame rate is available
+     *                               and it does not need to be used in calculations.
      */
     public VideoEncoderConfigDefaultResolver(@NonNull String mimeType,
             @NonNull Timebase inputTimebase, @NonNull VideoSpec videoSpec,
-            @NonNull Size surfaceSize, @Nullable Range<Integer> expectedFrameRateRange) {
+            @NonNull Size surfaceSize, @NonNull Range<Integer> expectedFrameRateRange) {
         mMimeType = mimeType;
         mInputTimebase = inputTimebase;
         mVideoSpec = videoSpec;
@@ -98,26 +107,23 @@
     }
 
     private int resolveFrameRate() {
-        Range<Integer> videoSpecFrameRateRange = mVideoSpec.getFrameRate();
-        // If the frame rate range isn't AUTO, we'll use the upper frame rate from the video spec
-        // as our default in an attempt to maximize the quality of the video. However, we need to
-        // ensure it is a valid frame rate, so clamp between 1 and 60fps.
-        int defaultFrameRate;
-        if (!VideoSpec.FRAME_RATE_RANGE_AUTO.equals(videoSpecFrameRateRange)) {
-            defaultFrameRate = VALID_FRAME_RATE_RANGE.clamp(videoSpecFrameRateRange.getUpper());
+        // If the operating frame rate range isn't unspecified, we'll use the upper frame rate from
+        // as our default in an attempt to maximize the quality of the video. Clamp the value to
+        // ensure it's a valid frame rate.
+        int resolvedFrameRate;
+        if (!Objects.equals(mExpectedFrameRateRange, SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED)) {
+            resolvedFrameRate = VALID_FRAME_RATE_RANGE.clamp(mExpectedFrameRateRange.getUpper());
         } else {
-            // We have no information to base the frame rate on. Use a standard default.
-            defaultFrameRate = VIDEO_FRAME_RATE_FIXED_DEFAULT;
+            // If the frame rate range is unspecified, return a hard coded common default.
+            resolvedFrameRate = VIDEO_FRAME_RATE_FIXED_DEFAULT;
         }
 
         Logger.d(TAG,
-                String.format("Frame rate default: %dfps. [Requested range: %s, "
-                                + "Expected operating range: %s]", defaultFrameRate,
-                        videoSpecFrameRateRange, mExpectedFrameRateRange));
+                String.format("Default resolved frame rate: %dfps. [Expected operating range: %s]",
+                        resolvedFrameRate, Objects.equals(mExpectedFrameRateRange,
+                                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED)
+                                ? mExpectedFrameRateRange : "<UNSPECIFIED>"));
 
-        return VideoConfigUtil.resolveFrameRate(
-                /*preferredRange=*/ videoSpecFrameRateRange,
-                /*exactFrameRateHint=*/ defaultFrameRate,
-                /*strictOperatingFpsRange=*/mExpectedFrameRateRange);
+        return resolvedFrameRate;
     }
 }
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
index 0009f26..dc374ae 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/config/VideoEncoderConfigVideoProfileResolver.java
@@ -20,15 +20,17 @@
 import android.util.Size;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.camera.core.Logger;
+import androidx.camera.core.SurfaceRequest;
 import androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy;
 import androidx.camera.core.impl.Timebase;
 import androidx.camera.video.VideoSpec;
 import androidx.camera.video.internal.encoder.VideoEncoderConfig;
 import androidx.core.util.Supplier;
 
+import java.util.Objects;
+
 /**
  * A {@link VideoEncoderConfig} supplier that resolves requested encoder settings from a
  * {@link VideoSpec} for the given surface {@link Size} using the provided
@@ -44,7 +46,6 @@
     private final VideoSpec mVideoSpec;
     private final Size mSurfaceSize;
     private final VideoProfileProxy mVideoProfile;
-    @Nullable
     private final Range<Integer> mExpectedFrameRateRange;
 
     /**
@@ -58,18 +59,19 @@
      * @param videoProfile     The {@link VideoProfileProxy} used to resolve automatic and range
      *                         settings.
      * @param expectedFrameRateRange The expected source frame rate range. This should act as an
-     *                               envelope for any frame rate calculated from {@code videoSpec
-     *                               } and {@code videoProfile} since the source should not
-     *                               produce frames at a frame rate outside this range. If {@code
-     *                               null}, then no information about the source frame rate is
-     *                               available and it does not need to be used in calculations.
+     *                               envelope for any frame rate calculated from {@code videoSpec}
+     *                               and {@code videoProfile} since the source should not
+     *                               produce frames at a frame rate outside this range. If
+     *                               equal to {@link SurfaceRequest#FRAME_RATE_RANGE_UNSPECIFIED},
+     *                               then no information about the source frame rate is available
+     *                               and it does not need to be used in calculations.
      */
     public VideoEncoderConfigVideoProfileResolver(@NonNull String mimeType,
             @NonNull Timebase inputTimebase,
             @NonNull VideoSpec videoSpec,
             @NonNull Size surfaceSize,
             @NonNull VideoProfileProxy videoProfile,
-            @Nullable Range<Integer> expectedFrameRateRange) {
+            @NonNull Range<Integer> expectedFrameRateRange) {
         mMimeType = mimeType;
         mInputTimebase = inputTimebase;
         mVideoSpec = videoSpec;
@@ -103,16 +105,21 @@
     }
 
     private int resolveFrameRate() {
-        Range<Integer> videoSpecFrameRateRange = mVideoSpec.getFrameRate();
         int videoProfileFrameRate = mVideoProfile.getFrameRate();
-        Logger.d(TAG,
-                String.format("Frame rate from video profile: %dfps. [Requested range: %s, "
-                        + "Expected operating range: %s]", videoProfileFrameRate,
-                        videoSpecFrameRateRange, mExpectedFrameRateRange));
+        int resolvedFrameRate;
+        if (!Objects.equals(mExpectedFrameRateRange, SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED)) {
+            resolvedFrameRate = mExpectedFrameRateRange.clamp(videoProfileFrameRate);
+        } else {
+            resolvedFrameRate = videoProfileFrameRate;
+        }
 
-        return VideoConfigUtil.resolveFrameRate(
-                /*preferredRange=*/ videoSpecFrameRateRange,
-                /*exactFrameRateHint=*/ videoProfileFrameRate,
-                /*strictOperatingFpsRange=*/mExpectedFrameRateRange);
+        Logger.d(TAG,
+                String.format("Resolved frame rate %dfps [Video profile frame rate: %dfps, "
+                                + "Expected operating range: %s]", resolvedFrameRate,
+                        videoProfileFrameRate, Objects.equals(mExpectedFrameRateRange,
+                                SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED)
+                                ? mExpectedFrameRateRange : "<UNSPECIFIED>"));
+
+        return resolvedFrameRate;
     }
 }
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
index d0e5fb9..48d03ab 100644
--- a/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
+++ b/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
@@ -43,9 +43,9 @@
 import androidx.camera.core.CameraSelector.LENS_FACING_BACK
 import androidx.camera.core.CameraSelector.LENS_FACING_FRONT
 import androidx.camera.core.CameraXConfig
-import androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY
 import androidx.camera.core.MirrorMode.MIRROR_MODE_OFF
 import androidx.camera.core.MirrorMode.MIRROR_MODE_ON
+import androidx.camera.core.MirrorMode.MIRROR_MODE_ON_FRONT_ONLY
 import androidx.camera.core.SurfaceRequest
 import androidx.camera.core.UseCase
 import androidx.camera.core.impl.CameraFactory
@@ -1038,6 +1038,27 @@
         )
     }
 
+    @Test
+    fun suggestedStreamSpecFrameRate_isPropagatedToSurfaceRequest() {
+        // [24, 24] is what will be chosen by the stream spec. By setting the target to another
+        // value, this ensures the SurfaceRequest is getting what comes from the stream spec rather
+        // than just from the target.
+        testSurfaceRequestContainsExpected(
+            targetFrameRate = FRAME_RATE_RANGE_FIXED_30,
+            expectedFrameRate = FRAME_RATE_RANGE_FIXED_24
+        )
+    }
+
+    @Test
+    fun unspecifiedStreamSpecFrameRate_sendsDefaultFrameRateToSurfaceRequest() {
+        // Currently we assume a fixed [30, 30] for VideoCapture since that is typically the fixed
+        // frame rate that most devices will choose for a video template. In the future we may
+        // try to query the device for this default frame rate.
+        testSurfaceRequestContainsExpected(
+            expectedFrameRate = FRAME_RATE_RANGE_FIXED_30
+        )
+    }
+
     private fun testSetTargetRotation_transformationInfoUpdated(
         lensFacing: Int = LENS_FACING_BACK,
         sensorRotationDegrees: Int = 0,
@@ -1260,34 +1281,63 @@
     private fun testAdjustCropRectToValidSize(
         quality: Quality = HD, // HD maps to 1280x720 (4:3)
         videoEncoderInfo: VideoEncoderInfo = createVideoEncoderInfo(),
-        cropRect: Rect,
-        expectedCropRect: Rect,
+        cropRect: Rect? = null,
+        expectedCropRect: Rect? = null
+    ) {
+        testSurfaceRequestContainsExpected(
+            quality = quality,
+            videoEncoderInfo = videoEncoderInfo,
+            cropRect = cropRect,
+            expectedCropRect = expectedCropRect
+        )
+    }
+
+    private fun testSurfaceRequestContainsExpected(
+        quality: Quality = HD, // HD maps to 1280x720 (4:3)
+        videoEncoderInfo: VideoEncoderInfo = createVideoEncoderInfo(),
+        cropRect: Rect? = null,
+        expectedCropRect: Rect? = null,
+        targetFrameRate: Range<Int>? = null,
+        expectedFrameRate: Range<Int> = SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED
     ) {
         // Arrange.
         setupCamera()
         createCameraUseCaseAdapter()
-        setSuggestedStreamSpec(quality)
+        setSuggestedStreamSpec(
+            quality,
+            expectedFrameRate = expectedFrameRate
+        )
         var surfaceRequest: SurfaceRequest? = null
         val videoOutput = createVideoOutput(
             mediaSpec = MediaSpec.builder().configureVideo {
                 it.setQualitySelector(QualitySelector.from(quality))
             }.build(),
-            surfaceRequestListener = { request, _ -> surfaceRequest = request }
+            surfaceRequestListener = { request, _ -> surfaceRequest = request },
         )
         val videoCapture = createVideoCapture(
             videoOutput,
-            videoEncoderInfoFinder = { videoEncoderInfo }
+            videoEncoderInfoFinder = { videoEncoderInfo },
+            targetFrameRate = targetFrameRate
         )
-        cameraUseCaseAdapter.setEffects(listOf(createFakeEffect()))
-        videoCapture.setViewPortCropRect(cropRect)
+
+        cropRect?.let {
+            cameraUseCaseAdapter.setEffects(listOf(createFakeEffect()))
+            videoCapture.setViewPortCropRect(it)
+        }
 
         // Act.
         addAndAttachUseCases(videoCapture)
 
         // Assert.
         assertThat(surfaceRequest).isNotNull()
-        assertThat(surfaceRequest!!.resolution).isEqualTo(rectToSize(expectedCropRect))
-        assertThat(videoCapture.cropRect).isEqualTo(expectedCropRect)
+        expectedCropRect?.let {
+            assertThat(surfaceRequest!!.resolution).isEqualTo(rectToSize(it))
+            assertThat(videoCapture.cropRect).isEqualTo(it)
+        }
+
+        if (expectedFrameRate != StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED) {
+            assertThat(surfaceRequest!!.expectedFrameRate).isEqualTo(expectedFrameRate)
+        }
     }
 
     private fun assertCustomOrderedResolutions(
@@ -1377,6 +1427,7 @@
         targetRotation: Int? = null,
         mirrorMode: Int? = null,
         targetResolution: Size? = null,
+        targetFrameRate: Range<Int>? = null,
         videoEncoderInfoFinder: Function<VideoEncoderConfig, VideoEncoderInfo> =
             Function { createVideoEncoderInfo() },
     ): VideoCapture<VideoOutput> = VideoCapture.Builder(videoOutput)
@@ -1385,6 +1436,7 @@
             targetRotation?.let { setTargetRotation(it) }
             mirrorMode?.let { setMirrorMode(it) }
             targetResolution?.let { setTargetResolution(it) }
+            targetFrameRate?.let { setTargetFrameRate(it) }
             setVideoEncoderInfoFinder(videoEncoderInfoFinder)
         }.build()
 
@@ -1409,8 +1461,14 @@
         return handler
     }
 
-    private fun setSuggestedStreamSpec(quality: Quality) {
-        setSuggestedStreamSpec(StreamSpec.builder(CAMERA_0_QUALITY_SIZE[quality]!!).build())
+    private fun setSuggestedStreamSpec(
+        quality: Quality,
+        expectedFrameRate: Range<Int> = StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED
+    ) {
+        setSuggestedStreamSpec(
+            StreamSpec.builder(CAMERA_0_QUALITY_SIZE[quality]!!)
+                .setExpectedFrameRateRange(expectedFrameRate).build()
+        )
     }
 
     private fun setSuggestedStreamSpec(streamSpec: StreamSpec) {
@@ -1476,6 +1534,9 @@
             HIGHEST to RESOLUTION_2160P,
         )
 
+        private val FRAME_RATE_RANGE_FIXED_24 = Range(24, 24)
+        private val FRAME_RATE_RANGE_FIXED_30 = Range(30, 30)
+
         private val CAMERA_0_SUPPORTED_RESOLUTION_MAP = mapOf(
             ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE to listOf(
                 // 4:3
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
index 96508df..0656d5e 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
@@ -34,7 +34,6 @@
 import androidx.camera.core.ImageProxy
 import androidx.camera.core.impl.ImageOutputConfig
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
-import androidx.camera.core.resolutionselector.HighResolution
 import androidx.camera.core.resolutionselector.ResolutionSelector
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraPipeConfigTestRule
@@ -259,6 +258,7 @@
         assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun defaultAspectRatioWillBeSet_whenRatioDefaultIsSet() = runBlocking {
         val useCase = ImageAnalysis.Builder()
@@ -271,6 +271,7 @@
         assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     @Test
     fun defaultAspectRatioWontBeSet_whenTargetResolutionIsSet() = runBlocking {
         assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK))
@@ -300,6 +301,7 @@
         assertThat(imageAnalysis.targetRotation).isEqualTo(Surface.ROTATION_90)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun targetResolutionIsUpdatedAfterTargetRotationIsUpdated() = runBlocking {
         val imageAnalysis = ImageAnalysis.Builder()
@@ -431,7 +433,7 @@
         assumeTrue(maxHighResolutionOutputSize != null)
 
         val resolutionSelector = ResolutionSelector.Builder()
-            .setHighResolutionEnabledFlags(HighResolution.FLAG_DEFAULT_MODE_ON)
+            .setHighResolutionEnabledFlag(ResolutionSelector.HIGH_RESOLUTION_FLAG_ON)
             .setResolutionFilter { _, _ ->
                 listOf(maxHighResolutionOutputSize)
             }
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index c86e5dd..2cb4ddf 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -62,7 +62,6 @@
 import androidx.camera.core.impl.utils.CameraOrientationUtil
 import androidx.camera.core.impl.utils.Exif
 import androidx.camera.core.internal.compat.workaround.ExifRotationAvailability
-import androidx.camera.core.resolutionselector.HighResolution
 import androidx.camera.core.resolutionselector.ResolutionSelector
 import androidx.camera.integration.core.util.CameraPipeUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
@@ -166,6 +165,7 @@
         }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun capturedImageHasCorrectSize() = runBlocking {
         val useCase = ImageCapture.Builder()
@@ -802,6 +802,7 @@
         assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun defaultAspectRatioWillBeSet_whenRatioDefaultIsSet() = runBlocking {
         val useCase = ImageCapture.Builder().setTargetAspectRatio(AspectRatio.RATIO_DEFAULT).build()
@@ -813,6 +814,7 @@
         assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     @Test
     fun defaultAspectRatioWontBeSet_whenTargetResolutionIsSet() = runBlocking {
         val useCase = ImageCapture.Builder()
@@ -845,6 +847,7 @@
         assertThat(imageCapture.targetRotation).isEqualTo(Surface.ROTATION_90)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun targetResolutionIsUpdatedAfterTargetRotationIsUpdated() = runBlocking {
         val imageCapture = ImageCapture.Builder()
@@ -865,6 +868,7 @@
         assertThat(newConfig.targetResolution).isEqualTo(expectedTargetResolution)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun capturedImageHasCorrectCroppingSizeWithoutSettingRotation() {
         val useCase = ImageCapture.Builder()
@@ -879,6 +883,7 @@
         )
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun capturedImageHasCorrectCroppingSizeSetRotationBuilder() {
         // Checks camera device sensor degrees to set correct target rotation value to make sure
@@ -898,6 +903,7 @@
         )
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun capturedImageHasCorrectCroppingSize_setUseCaseRotation90FromRotationInBuilder() {
         // Checks camera device sensor degrees to set correct target rotation value to make sure
@@ -1602,7 +1608,7 @@
         assumeTrue(maxHighResolutionOutputSize != null)
 
         val resolutionSelector = ResolutionSelector.Builder()
-            .setHighResolutionEnabledFlags(HighResolution.FLAG_DEFAULT_MODE_ON)
+            .setHighResolutionEnabledFlag(ResolutionSelector.HIGH_RESOLUTION_FLAG_ON)
             .setResolutionFilter { _, _ ->
                 listOf(maxHighResolutionOutputSize)
             }
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
index 5edc137..4586b00 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
@@ -105,6 +105,7 @@
         measureImageProcessing(CameraSelector.LENS_FACING_FRONT)
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     private fun measureImageProcessing(lensFacing: Int): Unit = runBlocking {
         // The log is used to profile the ImageProcessing performance. The log parser identifies
         // the log pattern "Image processing performance profiling" in the device output log.
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
index 43a50f5..79e2853 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
@@ -170,6 +170,7 @@
         ).that(latchForBarcodeDetect.await(DETECT_TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     private fun initImageAnalysis(lensFacing: Int): ImageAnalysis {
         val sensorOrientation = CameraUtil.getSensorOrientation(lensFacing)
         val isRotateNeeded = sensorOrientation!! % 180 != 0
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
index f7b75c4..ab2b0ab 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/PreviewTest.kt
@@ -33,7 +33,6 @@
 import androidx.camera.core.impl.ImageOutputConfig
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.core.internal.CameraUseCaseAdapter
-import androidx.camera.core.resolutionselector.HighResolution
 import androidx.camera.core.resolutionselector.ResolutionSelector
 import androidx.camera.testing.CameraPipeConfigTestRule
 import androidx.camera.testing.CameraUtil
@@ -328,6 +327,7 @@
         Truth.assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test
     fun defaultAspectRatioWillBeSet_whenRatioDefaultIsSet() {
         val useCase = Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_DEFAULT).build()
@@ -336,6 +336,7 @@
         Truth.assertThat(config.targetAspectRatio).isEqualTo(AspectRatio.RATIO_4_3)
     }
 
+    @Suppress("DEPRECATION") // legacy resolution API
     @Test
     fun defaultAspectRatioWontBeSet_whenTargetResolutionIsSet() {
         Assume.assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK))
@@ -555,7 +556,7 @@
         // Arrange.
         val resolutionSelector =
             ResolutionSelector.Builder()
-                .setHighResolutionEnabledFlags(HighResolution.FLAG_DEFAULT_MODE_ON)
+                .setHighResolutionEnabledFlag(ResolutionSelector.HIGH_RESOLUTION_FLAG_ON)
                 .setResolutionFilter { _, _ ->
                     listOf(maxHighResolutionOutputSize)
                 }
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/SurfaceOrientedMeteringPointFactoryTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/SurfaceOrientedMeteringPointFactoryTest.kt
index 2b7b471..4a3759a 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/SurfaceOrientedMeteringPointFactoryTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/camera2/SurfaceOrientedMeteringPointFactoryTest.kt
@@ -133,6 +133,7 @@
             }
     }
 
+    @Suppress("DEPRECATION") // test for legacy resolution API
     @Test(expected = IllegalStateException::class)
     fun createPointWithFoVUseCase_FailedNotBound() {
         Assume.assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK))
diff --git a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationScreen.java b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationScreen.java
index 3d72083..1e5233c 100644
--- a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationScreen.java
+++ b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationScreen.java
@@ -16,6 +16,9 @@
 
 package androidx.car.app.sample.navigation.common.car;
 
+import android.content.ComponentName;
+import android.content.Intent;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.car.app.CarContext;
@@ -34,8 +37,11 @@
 import androidx.car.app.navigation.model.RoutingInfo;
 import androidx.car.app.navigation.model.Step;
 import androidx.car.app.navigation.model.TravelEstimate;
+import androidx.car.app.notification.CarPendingIntent;
 import androidx.car.app.sample.navigation.common.R;
 import androidx.car.app.sample.navigation.common.model.Instruction;
+import androidx.car.app.suggestion.SuggestionManager;
+import androidx.car.app.suggestion.model.Suggestion;
 import androidx.core.graphics.drawable.IconCompat;
 
 import java.util.ArrayList;
@@ -133,6 +139,9 @@
     @NonNull
     @Override
     public Template onGetTemplate() {
+        // Send out suggestion when navigation screen start
+        createAndSendSuggestion();
+
         mSurfaceRenderer.updateMarkerVisibility(
                 /* showMarkers=*/ false, /* numMarkers=*/ 0, /* activeMarker=*/ -1);
 
@@ -340,4 +349,38 @@
                             }
                         });
     }
+
+    private void createAndSendSuggestion() {
+        CarIcon homeIcon = new CarIcon.Builder(IconCompat.createWithResource(
+                getCarContext(),
+                R.drawable.ic_home)).build();
+        CarIcon workIcon = new CarIcon.Builder(IconCompat.createWithResource(
+                getCarContext(),
+                R.drawable.ic_work)).build();
+
+        List<Suggestion> suggestionList = new ArrayList<>();
+        suggestionList.add(getSuggestion(R.string.suggestion_card_home_title,
+                R.string.suggestion_card_home_subtitle, homeIcon));
+        suggestionList.add(getSuggestion(R.string.suggestion_card_work_title,
+                R.string.suggestion_card_work_subtitle, workIcon));
+
+        getCarContext().getCarService(SuggestionManager.class)
+                .updateSuggestions(suggestionList);
+    }
+
+    private Suggestion getSuggestion(int title, int subtitle, CarIcon icon) {
+        return new Suggestion.Builder()
+                .setIdentifier("0")
+                .setTitle(getCarContext().getString(title))
+                .setSubtitle(getCarContext().getString(subtitle))
+                .setIcon(icon)
+                .setAction(
+                        CarPendingIntent.getCarApp(getCarContext(), 0,
+                                new Intent().setComponent(
+                                        new ComponentName(getCarContext(),
+                                                NavigationCarAppService.class))
+                                        .setAction(NavigationSession.EXECUTE_SCRIPT),
+                                0))
+                .build();
+    }
 }
diff --git a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationSession.java b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationSession.java
index 4fe2428..7dc4b57 100644
--- a/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationSession.java
+++ b/car/app/app-samples/navigation/common/src/main/java/androidx/car/app/sample/navigation/common/car/NavigationSession.java
@@ -45,6 +45,7 @@
 import androidx.car.app.navigation.model.Step;
 import androidx.car.app.navigation.model.TravelEstimate;
 import androidx.car.app.sample.navigation.common.R;
+import androidx.car.app.sample.navigation.common.model.DemoScripts;
 import androidx.car.app.sample.navigation.common.model.Instruction;
 import androidx.car.app.sample.navigation.common.nav.NavigationService;
 import androidx.core.graphics.drawable.IconCompat;
@@ -64,6 +65,8 @@
     static final String URI_SCHEME = "samples";
     static final String URI_HOST = "navigation";
 
+    static final String EXECUTE_SCRIPT = "EXECUTE_SCRIPT";
+
     @Nullable
     NavigationScreen mNavigationScreen;
 
@@ -259,6 +262,10 @@
             return;
         }
 
+        if (EXECUTE_SCRIPT.equals(intent.getAction())) {
+            executeScript(DemoScripts.getNavigateHome(getCarContext()));
+        }
+
         // Process the intent from DeepLinkNotificationReceiver. Bring the routing screen back to
         // the
         // top if any other screens were pushed onto it.
diff --git a/car/app/app-samples/navigation/common/src/main/res/drawable/ic_home.xml b/car/app/app-samples/navigation/common/src/main/res/drawable/ic_home.xml
new file mode 100644
index 0000000..685d37d
--- /dev/null
+++ b/car/app/app-samples/navigation/common/src/main/res/drawable/ic_home.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="960" android:viewportHeight="960">
+    <path android:fillColor="@android:color/white" android:pathData="M220,780L370,780L370,530L590,530L590,780L740,780L740,390L480,195L220,390L220,780ZM160,840L160,360L480,120L800,360L800,840L530,840L530,590L430,590L430,840L160,840ZM480,487L480,487L480,487L480,487L480,487L480,487L480,487L480,487L480,487L480,487Z"/>
+</vector>
\ No newline at end of file
diff --git a/car/app/app-samples/navigation/common/src/main/res/drawable/ic_work.xml b/car/app/app-samples/navigation/common/src/main/res/drawable/ic_work.xml
new file mode 100644
index 0000000..29d7120
--- /dev/null
+++ b/car/app/app-samples/navigation/common/src/main/res/drawable/ic_work.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="960" android:viewportHeight="960">
+    <path android:fillColor="@android:color/white" android:pathData="M140,840Q116,840 98,822Q80,804 80,780L80,300Q80,276 98,258Q116,240 140,240L320,240L320,140Q320,116 338,98Q356,80 380,80L580,80Q604,80 622,98Q640,116 640,140L640,240L820,240Q844,240 862,258Q880,276 880,300L880,780Q880,804 862,822Q844,840 820,840L140,840ZM140,780L820,780Q820,780 820,780Q820,780 820,780L820,300Q820,300 820,300Q820,300 820,300L140,300Q140,300 140,300Q140,300 140,300L140,780Q140,780 140,780Q140,780 140,780ZM380,240L580,240L580,140Q580,140 580,140Q580,140 580,140L380,140Q380,140 380,140Q380,140 380,140L380,240ZM140,780Q140,780 140,780Q140,780 140,780L140,300Q140,300 140,300Q140,300 140,300L140,300Q140,300 140,300Q140,300 140,300L140,780Q140,780 140,780Q140,780 140,780L140,780Z"/>
+</vector>
\ No newline at end of file
diff --git a/car/app/app-samples/navigation/common/src/main/res/values/strings.xml b/car/app/app-samples/navigation/common/src/main/res/values/strings.xml
index 27a95a0..e86bd1f 100644
--- a/car/app/app-samples/navigation/common/src/main/res/values/strings.xml
+++ b/car/app/app-samples/navigation/common/src/main/res/values/strings.xml
@@ -47,4 +47,10 @@
   <string name="no_action_toast_msg">No button pressed!</string>
   <string name="alert_timeout_toast_msg">Alert is timed out!</string>
   <string name="alert_not_supported">Alert is not supported, use HUN instead</string>
+
+  <!-- Suggestion card -->
+  <string name="suggestion_card_home_title">Home</string>
+  <string name="suggestion_card_home_subtitle">3 km &#11825; 10th street</string>
+  <string name="suggestion_card_work_title">Work</string>
+  <string name="suggestion_card_work_subtitle">5 km &#11825; 3rd street</string>
 </resources>
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateDemoScreen.java
index 63300fa..b6f22ed 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateDemoScreen.java
@@ -120,20 +120,17 @@
                             ICON_RES_IDS[i])).build())
                     .setContentId(contentId);
             if (TextUtils.isEmpty(mActiveContentId) && i == 0) {
-                tabBuilder.setActive(true);
+                mActiveContentId = contentId;
                 mTabTemplateBuilder.setTabContents(tabContents);
             } else if (TextUtils.equals(mActiveContentId, contentId)) {
-                tabBuilder.setActive(true);
                 mTabTemplateBuilder.setTabContents(tabContents);
-            } else {
-                tabBuilder.setActive(false);
             }
 
             Tab tab = tabBuilder.build();
             mTabs.put(tab.getContentId(), tab);
             mTabTemplateBuilder.addTab(tab);
         }
-        return mTabTemplateBuilder.build();
+        return mTabTemplateBuilder.setActiveTabContentId(mActiveContentId).build();
     }
 
     private ListTemplate createListTemplate() {
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateLoadingDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateLoadingDemoScreen.java
index ee434b7..2c961fd 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateLoadingDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/screens/templatelayouts/tabtemplates/TabTemplateLoadingDemoScreen.java
@@ -86,18 +86,14 @@
                             sIconResIds[i])).build())
                     .setContentId(contentId);
             if (TextUtils.isEmpty(mActiveContentId) && i == 0) {
-                tabBuilder.setActive(true);
-            } else if (TextUtils.equals(mActiveContentId, contentId)) {
-                tabBuilder.setActive(true);
-            } else {
-                tabBuilder.setActive(false);
+                mActiveContentId = contentId;
             }
 
             Tab tab = tabBuilder.build();
             mTabs.put(tab.getContentId(), tab);
             mTabTemplateBuilder.addTab(tab);
 
-            if (tab.isActive()) {
+            if (TextUtils.equals(mActiveContentId, contentId)) {
                 if (i == 0) {
                     mTabTemplateBuilder.setLoading(true);
                 } else {
@@ -105,7 +101,7 @@
                 }
             }
         }
-        return mTabTemplateBuilder.build();
+        return mTabTemplateBuilder.setActiveTabContentId(mActiveContentId).build();
     }
 
     private TabContents createSearchTab() {
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-or/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-or/strings.xml
index b80fcd6..d9d3573 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-or/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-or/strings.xml
@@ -38,7 +38,7 @@
     <string name="settings_action_title" msgid="8616900063253887861">"ସେଟିଂସ"</string>
     <string name="accept_action_title" msgid="4899660585470647578">"ଗ୍ରହଣ କରନ୍ତୁ"</string>
     <string name="reject_action_title" msgid="6730366705938402668">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
-    <string name="ok_action_title" msgid="7128494973966098611">"ଠିକ୍ ଅଛି"</string>
+    <string name="ok_action_title" msgid="7128494973966098611">"ଠିକ ଅଛି"</string>
     <string name="throw_action_title" msgid="7163710562670220163">"ଥ୍ରୋ କରନ୍ତୁ"</string>
     <string name="commute_action_title" msgid="2585755255290185096">"ଯାତାୟାତ"</string>
     <string name="sign_out_action_title" msgid="1653943000866713010">"ସାଇନ ଆଉଟ କରନ୍ତୁ"</string>
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 9812488..33ffc83 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -1170,10 +1170,13 @@
     method public androidx.car.app.model.ActionStrip? getActionStrip();
     method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
     method public androidx.car.app.model.Action? getHeaderAction();
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
     method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
     method public androidx.car.app.model.ItemList? getSingleList();
     method public androidx.car.app.model.CarText? getTitle();
     method public boolean isLoading();
+    field @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_CIRCLE = 2; // 0x2
+    field @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_UNSET = 1; // 0x1
     field @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_LARGE = 4; // 0x4
     field @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_MEDIUM = 2; // 0x2
     field @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_SMALL = 1; // 0x1
@@ -1185,6 +1188,7 @@
     method public androidx.car.app.model.GridTemplate build();
     method public androidx.car.app.model.GridTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
     method public androidx.car.app.model.GridTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemImageShape(int);
     method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemSize(int);
     method public androidx.car.app.model.GridTemplate.Builder setLoading(boolean);
     method public androidx.car.app.model.GridTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
@@ -1525,14 +1529,14 @@
     method public String getContentId();
     method public androidx.car.app.model.CarIcon getIcon();
     method public androidx.car.app.model.CarText getTitle();
-    method public boolean isActive();
+    method @Deprecated public boolean isActive();
     method public androidx.car.app.model.Tab.Builder toBuilder();
   }
 
   public static final class Tab.Builder {
     ctor public Tab.Builder();
     method public androidx.car.app.model.Tab build();
-    method public androidx.car.app.model.Tab.Builder setActive(boolean);
+    method @Deprecated public androidx.car.app.model.Tab.Builder setActive(boolean);
     method public androidx.car.app.model.Tab.Builder setContentId(String);
     method public androidx.car.app.model.Tab.Builder setIcon(androidx.car.app.model.CarIcon);
     method public androidx.car.app.model.Tab.Builder setTitle(CharSequence);
@@ -1554,6 +1558,7 @@
   }
 
   @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(6) public class TabTemplate implements androidx.car.app.model.Template {
+    method public String getActiveTabContentId();
     method public androidx.car.app.model.Action getHeaderAction();
     method public androidx.car.app.model.TabCallbackDelegate getTabCallbackDelegate();
     method public androidx.car.app.model.TabContents getTabContents();
@@ -1563,8 +1568,10 @@
 
   public static final class TabTemplate.Builder {
     ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate.TabCallback);
+    ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate);
     method public androidx.car.app.model.TabTemplate.Builder addTab(androidx.car.app.model.Tab);
     method public androidx.car.app.model.TabTemplate build();
+    method public androidx.car.app.model.TabTemplate.Builder setActiveTabContentId(String);
     method public androidx.car.app.model.TabTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
     method public androidx.car.app.model.TabTemplate.Builder setLoading(boolean);
     method public androidx.car.app.model.TabTemplate.Builder setTabContents(androidx.car.app.model.TabContents);
diff --git a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
index eac356c..2706095 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/GridTemplate.java
@@ -66,8 +66,6 @@
      * <p>The host decides how to map these size buckets to dimensions. The grid item image size
      * and grid item width will vary by bucket, and the number of items per row
      * will be adjusted according to bucket and screen size.
-     *
-     * @hide
      */
     @ExperimentalCarApi
     @RequiresCarApi(7)
@@ -109,6 +107,43 @@
     @RequiresCarApi(7)
     public static final int ITEM_SIZE_LARGE = (1 << 2);
 
+    /**
+     * The shape of each grid item image contained within this GridTemplate.
+     *
+     * <p>Grid item images will be cropped by the host to match the shape type.
+     */
+    @ExperimentalCarApi
+    @RequiresCarApi(7)
+    @IntDef(
+            value = {
+                    ITEM_IMAGE_SHAPE_UNSET,
+                    ITEM_IMAGE_SHAPE_CIRCLE,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(LIBRARY)
+    public @interface ItemImageShape {
+    }
+
+    /**
+     * Represents a preference to keep the images as-is without modifying their shape.
+     *
+     * <p>This is the default setting.
+     *
+     * @see GridTemplate.Builder#setItemImageShape(int)
+     */
+    @ExperimentalCarApi
+    @RequiresCarApi(7)
+    public static final int ITEM_IMAGE_SHAPE_UNSET = (1 << 0);
+
+    /**
+     * Represents a preference to crop all grid item images into the shape of a circle.
+     *
+     * @see GridTemplate.Builder#setItemImageShape(int)
+     */
+    @ExperimentalCarApi
+    @RequiresCarApi(7)
+    public static final int ITEM_IMAGE_SHAPE_CIRCLE = (1 << 1);
+
     private final boolean mIsLoading;
     @Nullable
     private final CarText mTitle;
@@ -121,6 +156,8 @@
     private final List<Action> mActions;
     @ItemSize
     private final int mItemSize;
+    @ItemImageShape
+    private final int mItemImageShape;
 
     /**
      * Returns the title of the template or {@code null} if not set.
@@ -197,6 +234,20 @@
         return mItemSize;
     }
 
+    /**
+     * Returns the item image shape.
+     *
+     * <p>All item images in the grid are cropped into the specified shape.
+     *
+     * @see GridTemplate.Builder#setItemImageShape(int)
+     */
+    @ExperimentalCarApi
+    @ItemImageShape
+    @RequiresCarApi(7)
+    public int getItemImageShape() {
+        return mItemImageShape;
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -206,7 +257,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mIsLoading, mTitle, mHeaderAction, mSingleList, mActionStrip,
-                mItemSize);
+                mItemSize, mItemImageShape);
     }
 
     @Override
@@ -225,7 +276,8 @@
                 && Objects.equals(mSingleList, otherTemplate.mSingleList)
                 && Objects.equals(mActionStrip, otherTemplate.mActionStrip)
                 && Objects.equals(mActions, otherTemplate.mActions)
-                && mItemSize == otherTemplate.mItemSize;
+                && mItemSize == otherTemplate.mItemSize
+                && mItemImageShape == otherTemplate.mItemImageShape;
     }
 
     GridTemplate(Builder builder) {
@@ -236,6 +288,7 @@
         mActionStrip = builder.mActionStrip;
         mActions = CollectionUtils.unmodifiableCopy(builder.mActions);
         mItemSize = builder.mItemSize;
+        mItemImageShape = builder.mItemImageShape;
     }
 
     /** Constructs an empty instance, used by serialization code. */
@@ -248,6 +301,7 @@
         mActionStrip = null;
         mActions = Collections.emptyList();
         mItemSize = ITEM_SIZE_SMALL;
+        mItemImageShape = ITEM_IMAGE_SHAPE_UNSET;
     }
 
     /** A builder of {@link GridTemplate}. */
@@ -265,6 +319,7 @@
         final List<Action> mActions = new ArrayList<>();
         @ItemSize
         int mItemSize = ITEM_SIZE_SMALL;
+        @ItemImageShape int mItemImageShape = ITEM_IMAGE_SHAPE_UNSET;
 
         /**
          * Sets whether the template is in a loading state.
@@ -393,6 +448,22 @@
         }
 
         /**
+         * Sets the item image shape for this template.
+         *
+         * <p>Grid item images will all be cropped to the specified shape. If set to
+         * ITEM_IMAGE_SHAPE_UNSET, the images will be rendered as-is without changing the shape.
+         *
+         * <p>If not set, default to ITEM_IMAGE_SHAPE_UNSET.
+         */
+        @ExperimentalCarApi
+        @NonNull
+        @RequiresCarApi(7)
+        public Builder setItemImageShape(@ItemImageShape int itemImageShape) {
+            mItemImageShape = itemImageShape;
+            return this;
+        }
+
+        /**
          * Constructs the template defined by this builder.
          *
          * <h4>Requirements</h4>
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Tab.java b/car/app/app/src/main/java/androidx/car/app/model/Tab.java
index 732d534..b6f6089 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Tab.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Tab.java
@@ -22,10 +22,10 @@
 import androidx.annotation.Nullable;
 import androidx.car.app.annotations.CarProtocol;
 import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.KeepFields;
 import androidx.car.app.annotations.RequiresCarApi;
 import androidx.car.app.model.constraints.CarIconConstraints;
 import androidx.car.app.model.constraints.CarTextConstraints;
-import androidx.car.app.annotations.KeepFields;
 
 import java.util.Objects;
 
@@ -84,7 +84,9 @@
      * Indicates if this is the currently active tab.
      *
      * @see Tab.Builder#setActive(boolean)
+     * @deprecated use {@link TabTemplate#getActiveTabContentId()} instead.
      */
+    @Deprecated
     public boolean isActive() {
         return mIsActive;
     }
@@ -226,8 +228,11 @@
 
         /**
          * Sets the active state of the tab.
+         *
+         * @deprecated use {@link TabTemplate.Builder#setActiveTabContentId(String)} instead.
          */
         @NonNull
+        @Deprecated
         public Tab.Builder setActive(boolean isActive) {
             mIsActive = isActive;
             return this;
diff --git a/car/app/app/src/main/java/androidx/car/app/model/TabTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/TabTemplate.java
index e3fb36f..1a55793 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/TabTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/TabTemplate.java
@@ -24,11 +24,12 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.car.app.Screen;
 import androidx.car.app.annotations.CarProtocol;
 import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.KeepFields;
 import androidx.car.app.annotations.RequiresCarApi;
 import androidx.car.app.model.constraints.TabsConstraints;
-import androidx.car.app.annotations.KeepFields;
 import androidx.car.app.utils.CollectionUtils;
 
 import java.util.ArrayList;
@@ -81,6 +82,8 @@
     private final TabContents mTabContents;
     @Nullable
     private final List<Tab> mTabs;
+    @Nullable
+    private final String mActiveTabContentId;
 
     /**
      * Returns the {@link Action} that is set to be displayed in the header of the template, or
@@ -126,6 +129,14 @@
         return requireNonNull(mTabCallbackDelegate);
     }
 
+    /**
+     * Returns the {@link Tab#getContentId()} for the active tab.
+     */
+    @NonNull
+    public String getActiveTabContentId() {
+        return requireNonNull(mActiveTabContentId);
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -134,7 +145,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mIsLoading, mHeaderAction, mTabs, mTabContents);
+        return Objects.hash(mIsLoading, mHeaderAction, mTabs, mTabContents, mActiveTabContentId);
     }
 
     @Override
@@ -150,7 +161,8 @@
         return mIsLoading == otherTemplate.mIsLoading
                 && Objects.equals(mHeaderAction, otherTemplate.mHeaderAction)
                 && Objects.equals(mTabs, otherTemplate.mTabs)
-                && Objects.equals(mTabContents, otherTemplate.mTabContents);
+                && Objects.equals(mTabContents, otherTemplate.mTabContents)
+                && Objects.equals(mActiveTabContentId, otherTemplate.getActiveTabContentId());
     }
 
     TabTemplate(TabTemplate.Builder builder) {
@@ -159,6 +171,7 @@
         mTabs = CollectionUtils.unmodifiableCopy(builder.mTabs);
         mTabContents = builder.mTabContents;
         mTabCallbackDelegate = builder.mTabCallbackDelegate;
+        mActiveTabContentId = builder.mActiveTabContentId;
     }
 
     /** Constructs an empty instance, used by serialization code. */
@@ -168,6 +181,7 @@
         mTabs = Collections.emptyList();
         mTabContents = null;
         mTabCallbackDelegate = null;
+        mActiveTabContentId = null;
     }
 
     /** A builder of {@link TabTemplate}. */
@@ -180,10 +194,13 @@
         @Nullable
         Action mHeaderAction;
 
-        final List<Tab> mTabs = new ArrayList<>();
+        final List<Tab> mTabs;
         @Nullable
         TabContents mTabContents;
 
+        @Nullable
+        String mActiveTabContentId;
+
         /**
          * Sets whether the template is in a loading state.
          *
@@ -234,6 +251,19 @@
         }
 
         /**
+         * Stores the given {@code contentId} as the "active tab" to show on the screen. The given
+         * ID must match a tab that was added by {@link #addTab(Tab)}.
+         */
+        @NonNull
+        public TabTemplate.Builder setActiveTabContentId(@NonNull String contentId) {
+            if (requireNonNull(contentId).isEmpty()) {
+                throw new IllegalArgumentException("The content ID cannot be null or empty");
+            }
+            mActiveTabContentId = contentId;
+            return this;
+        }
+
+        /**
          * Adds an {@link Tab} to display in the template.
          *
          * @throws NullPointerException if {@code tab} is {@code null}
@@ -274,8 +304,14 @@
                                 + "contents");
             }
 
-            if (hasTabs) {
-                TabsConstraints.DEFAULT.validateOrThrow(mTabs);
+            if (hasTabs && mActiveTabContentId == null) {
+                throw new IllegalStateException(
+                        "Template requires setting content ID for the active tab when not in "
+                                + "Loading state");
+            }
+
+            if (hasTabs && mActiveTabContentId != null) {
+                TabsConstraints.DEFAULT.validateOrThrow(mTabs, mActiveTabContentId);
             }
 
             if (!mIsLoading && mHeaderAction == null) {
@@ -292,6 +328,17 @@
         @SuppressLint("ExecutorRegistration")
         public Builder(@NonNull TabCallback callback) {
             mTabCallbackDelegate = TabCallbackDelegateImpl.create(requireNonNull(callback));
+            mTabs = new ArrayList<>();
+        }
+
+        /** Creates a new {@link Builder}, populated from the input {@link TabTemplate} */
+        public Builder(@NonNull TabTemplate tabTemplate) {
+            mIsLoading = tabTemplate.isLoading();
+            mHeaderAction = tabTemplate.getHeaderAction();
+            mTabs = new ArrayList<>(tabTemplate.getTabs());
+            mTabContents = tabTemplate.getTabContents();
+            mTabCallbackDelegate = tabTemplate.getTabCallbackDelegate();
+            mActiveTabContentId = tabTemplate.getActiveTabContentId();
         }
     }
 }
diff --git a/car/app/app/src/main/java/androidx/car/app/model/constraints/TabsConstraints.java b/car/app/app/src/main/java/androidx/car/app/model/constraints/TabsConstraints.java
index 9b089a6..d80ab48 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/constraints/TabsConstraints.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/constraints/TabsConstraints.java
@@ -22,7 +22,9 @@
 import androidx.car.app.annotations.RequiresCarApi;
 import androidx.car.app.model.Tab;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Encapsulates the constraints to apply when creating {@link TabTemplate}.
@@ -51,29 +53,36 @@
      *
      * @throws IllegalArgumentException if the constraints are not met
      */
-    public void validateOrThrow(@NonNull List<Tab> tabs) {
+    public void validateOrThrow(@NonNull List<Tab> tabs, @NonNull String activeTabContentId) {
         if (tabs.size() < mMinTabs) {
             throw new IllegalArgumentException(
-                    "Number of tabs set do not meet the minimum requirement of " + mMinTabs
-                            + " tabs");
+                    "There must be at least " + mMinTabs + " tab(s) added, but only found "
+                            + tabs.size());
         }
 
         if (tabs.size() > mMaxTabs) {
             throw new IllegalArgumentException(
-                    "Number of tabs set exceed the maximum allowed size of " + mMaxTabs);
+                    "There cannot be more than " + mMaxTabs + " tabs added, found " + tabs.size());
         }
 
-        int numOfActiveTabs = 0;
+        boolean hasTabWithActiveTabContentId = false;
+        Set<String> contentIdSet = new HashSet<>();
         for (Tab tab : tabs) {
-            if (tab.isActive()) {
-                numOfActiveTabs++;
+            if (activeTabContentId.equals(tab.getContentId())) {
+                hasTabWithActiveTabContentId = true;
+            }
+            if (!contentIdSet.add(tab.getContentId())) {
+                throw new IllegalArgumentException(
+                        "Found duplicate tab ID: " + tab.getContentId() + ". Each tab must have a"
+                                + " unique ID."
+                );
             }
         }
-        if (numOfActiveTabs == 0) {
-            throw new IllegalArgumentException("An active tab is required");
-        }
-        if (numOfActiveTabs > 1) {
-            throw new IllegalArgumentException("Only one active tab is allowed");
+
+        if (!hasTabWithActiveTabContentId) {
+            throw new IllegalArgumentException(
+                    "There is no tab with content ID matching the active tab content ID set on "
+                            + "the template");
         }
     }
 
diff --git a/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
index 9dc5d83..bafe3a7 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/GridTemplateTest.java
@@ -240,6 +240,23 @@
     }
 
     @Test
+    public void createInstance_defaultItemImageShape() {
+        ItemList list = TestUtils.getGridItemList(2);
+        GridTemplate template = new GridTemplate.Builder().setSingleList(list).build();
+        assertThat(template.getItemImageShape()).isEqualTo(GridTemplate.ITEM_IMAGE_SHAPE_UNSET);
+    }
+
+    @Test
+    public void createInstance_setItemImageShape() {
+        ItemList list = TestUtils.getGridItemList(2);
+        GridTemplate template =
+                new GridTemplate.Builder()
+                        .setSingleList(list)
+                        .setItemImageShape(GridTemplate.ITEM_IMAGE_SHAPE_CIRCLE).build();
+        assertThat(template.getItemImageShape()).isEqualTo(GridTemplate.ITEM_IMAGE_SHAPE_CIRCLE);
+    }
+
+    @Test
     public void equals() {
         ItemList itemList = new ItemList.Builder().build();
         String title = "title";
@@ -366,7 +383,23 @@
                         .setLoading(true)
                         .setItemSize(GridTemplate.ITEM_SIZE_SMALL)
                         .build();
+        assertThat(template1).isNotEqualTo(template2);
+    }
 
+    @Test
+    public void notEquals_differentItemImageShape() {
+        ItemList itemList = new ItemList.Builder().build();
+
+        GridTemplate template1 =
+                new GridTemplate.Builder()
+                        .setSingleList(itemList)
+                        .setItemImageShape(GridTemplate.ITEM_IMAGE_SHAPE_CIRCLE)
+                        .build();
+        GridTemplate template2 =
+                new GridTemplate.Builder()
+                        .setSingleList(itemList)
+                        .setItemImageShape(GridTemplate.ITEM_IMAGE_SHAPE_UNSET)
+                        .build();
         assertThat(template1).isNotEqualTo(template2);
     }
 }
diff --git a/car/app/app/src/test/java/androidx/car/app/model/TabTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/TabTemplateTest.java
index 8d1cbd8..046f416 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/TabTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/TabTemplateTest.java
@@ -52,6 +52,8 @@
                             .build())
             .build();
 
+    private static final String ACTIVE_TAB_CONTENT_ID = "ID_ACTIVE";
+
     @Test
     public void createInstance_emptyTemplate_notLoading_Throws() {
         assertThrows(
@@ -69,8 +71,9 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setLoading(true)
-                                .addTab(getTab("TAB_1", true))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -81,7 +84,21 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_1", true))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
+                                .build());
+    }
+
+    @Test
+    public void createInstance_activeTabContentIdNotSet_Throws() {
+        assertThrows(
+                IllegalStateException.class,
+                () ->
+                        new TabTemplate.Builder(mMockTabCallback)
+                                .setHeaderAction(Action.APP_ICON)
+                                .addTab(getTab("TAB_1", "ID_1"))
+                                .addTab(getTab("TAB_2", "ID_2"))
                                 .setTabContents(TAB_CONTENTS)
                                 .build());
     }
@@ -93,9 +110,24 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_1", true))
-                                .addTab(getTab("TAB_2", true))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
+                                .build());
+    }
+
+    @Test
+    public void createInstance_noActiveTab_Throws() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () ->
+                        new TabTemplate.Builder(mMockTabCallback)
+                                .setHeaderAction(Action.APP_ICON)
+                                .addTab(getTab("TAB_1", "ID_1"))
+                                .addTab(getTab("TAB_2", "ID_2"))
+                                .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -106,12 +138,30 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_1", true))
-                                .addTab(getTab("TAB_2", false))
-                                .addTab(getTab("TAB_3", false))
-                                .addTab(getTab("TAB_4", false))
-                                .addTab(getTab("TAB_5", false))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", "ID_2"))
+                                .addTab(getTab("TAB_3", "ID_3"))
+                                .addTab(getTab("TAB_4", "ID_4"))
+                                .addTab(getTab("TAB_5", "ID_5"))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
+                                .build());
+    }
+
+    @Test
+    public void createInstance_multipleTabsWithSameContentId_Throws() {
+        String duplicateId = "ID_DUPLICATE";
+        assertThrows(
+                IllegalArgumentException.class,
+                () ->
+                        new TabTemplate.Builder(mMockTabCallback)
+                                .setHeaderAction(Action.APP_ICON)
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", duplicateId))
+                                .addTab(getTab("TAB_3", duplicateId))
+                                .addTab(getTab("TAB_4", "ID_4"))
+                                .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -122,9 +172,10 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.BACK)
-                                .addTab(getTab("TAB_1", true))
-                                .addTab(getTab("TAB_2", false))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", "ID_2"))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -135,8 +186,9 @@
                 () ->
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_1", true))
-                                .addTab(getTab("TAB_2", false))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", "ID_2"))
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -144,16 +196,18 @@
     public void equals() {
         TabTemplate template1 = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         TabTemplate template2 = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertEquals(template1, template2);
@@ -163,18 +217,20 @@
     public void notEquals_differentTabs() {
         TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", "ID_1"))
+                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertThat(template)
                 .isNotEqualTo(
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_2", true))
-                                .addTab(getTab("TAB_3", false))
+                                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_3", "ID_3"))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -182,19 +238,21 @@
     public void notEquals_differentNumberOfTabs() {
         TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
-                .addTab(getTab("TAB_3", false))
+                .addTab(getTab("TAB_1", "ID_1"))
+                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_3", "ID_3"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertThat(template)
                 .isNotEqualTo(
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_2", true))
-                                .addTab(getTab("TAB_3", false))
+                                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_3", "ID_3"))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -202,16 +260,18 @@
     public void notEquals_differentActiveTab() {
         TabTemplate template1 = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         TabTemplate template2 = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", false))
-                .addTab(getTab("TAB_2", true))
+                .addTab(getTab("TAB_1", "ID_1"))
+                .addTab(getTab("TAB_2", ACTIVE_TAB_CONTENT_ID))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertNotEquals(template1, template2);
@@ -226,18 +286,20 @@
 
         TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
                 .setTabContents(new TabContents.Builder(listTemplate).build())
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertThat(template)
                 .isNotEqualTo(
                         new TabTemplate.Builder(mMockTabCallback)
                                 .setHeaderAction(Action.APP_ICON)
-                                .addTab(getTab("TAB_1", true))
-                                .addTab(getTab("TAB_2", false))
+                                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                                .addTab(getTab("TAB_2", "ID_2"))
                                 .setTabContents(TAB_CONTENTS)
+                                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                                 .build());
     }
 
@@ -245,9 +307,10 @@
     public void createInstance_twoTabs_valid() {
         TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertEquals(template.getTabs().size(), 2);
@@ -257,23 +320,57 @@
     public void createInstance_fourTabs_valid() {
         TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
                 .setHeaderAction(Action.APP_ICON)
-                .addTab(getTab("TAB_1", true))
-                .addTab(getTab("TAB_2", false))
-                .addTab(getTab("TAB_3", false))
-                .addTab(getTab("TAB_4", false))
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
+                .addTab(getTab("TAB_3", "ID_3"))
+                .addTab(getTab("TAB_4", "ID_4"))
                 .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
                 .build();
 
         assertEquals(template.getTabs().size(), 4);
     }
 
-    private static Tab getTab(String title, boolean isActive) {
+    @Test
+    public void copy_createsEquivalentInstance() {
+        TabTemplate template1 = new TabTemplate.Builder(mMockTabCallback)
+                .setHeaderAction(Action.APP_ICON)
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
+                .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
+                .build();
+
+        TabTemplate template2 = new TabTemplate.Builder(template1).build();
+
+        assertEquals(template1, template2);
+    }
+
+    @Test
+    public void copy_fieldsCanBeOverwritten() {
+        TabTemplate template = new TabTemplate.Builder(mMockTabCallback)
+                .setHeaderAction(Action.APP_ICON)
+                .addTab(getTab("TAB_1", ACTIVE_TAB_CONTENT_ID))
+                .addTab(getTab("TAB_2", "ID_2"))
+                .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId(ACTIVE_TAB_CONTENT_ID)
+                .build();
+
+        // Verify fields can be overwritten (no crash)
+        new TabTemplate.Builder(template)
+                .setHeaderAction(Action.APP_ICON)
+                .addTab(getTab("TAB_3", "ID_3"))
+                .setTabContents(TAB_CONTENTS)
+                .setActiveTabContentId("ID_3")
+                .build();
+    }
+
+    private static Tab getTab(String title, String contentId) {
         return new Tab.Builder()
-                .setContentId(title)
+                .setContentId(contentId)
                 .setIcon(TestUtils.getTestCarIcon(
                         ApplicationProvider.getApplicationContext(),
                         "ic_test_1"))
-                .setActive(isActive)
                 .setTitle(title)
                 .build();
     }
diff --git a/car/app/app/src/test/java/androidx/car/app/model/TabTest.java b/car/app/app/src/test/java/androidx/car/app/model/TabTest.java
index 702c572..14a5e80 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/TabTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/TabTest.java
@@ -17,7 +17,6 @@
 package androidx.car.app.model;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 
@@ -92,7 +91,7 @@
                 .setContentId("id")
                 .build();
 
-        assertFalse(tab.isActive());
+        assertEquals(tab.getContentId(), "id");
     }
 
     @Test
@@ -103,7 +102,6 @@
                         ApplicationProvider.getApplicationContext(),
                         "ic_test_1"))
                 .setContentId("id")
-                .setActive(false)
                 .build();
 
         assertEquals(tab, TEST_TAB);
@@ -140,11 +138,4 @@
 
         assertNotEquals(tab, TEST_TAB);
     }
-
-    @Test
-    public void notEquals_differentActiveState() {
-        Tab tab = TEST_TAB.toBuilder().setActive(true).build();
-
-        assertNotEquals(tab, TEST_TAB);
-    }
 }
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt
index e891076..83ab1d1 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt
@@ -20,7 +20,6 @@
 import androidx.collection.internal.idealLongArraySize
 import kotlin.DeprecationLevel.HIDDEN
 import kotlin.jvm.JvmField
-import kotlin.jvm.JvmOverloads
 import kotlin.jvm.JvmSynthetic
 
 private val DELETED = Any()
@@ -54,7 +53,7 @@
  * requiring any additional array allocations.
  */
 public expect open class LongSparseArray<E>
-@JvmOverloads public constructor(initialCapacity: Int = 10) {
+public constructor(initialCapacity: Int = 10) {
     @JvmSynthetic // Hide from Java callers.
     @JvmField
     internal var garbage: Boolean
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/SparseArrayCompat.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/SparseArrayCompat.kt
index 7bbfdef..817f261 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/SparseArrayCompat.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/SparseArrayCompat.kt
@@ -19,7 +19,6 @@
 import androidx.collection.internal.binarySearch
 import androidx.collection.internal.idealIntArraySize
 import kotlin.jvm.JvmField
-import kotlin.jvm.JvmOverloads
 import kotlin.jvm.JvmSynthetic
 import kotlin.math.min
 
@@ -62,7 +61,7 @@
  * 0, the sparse array will be initialized with a light-weight representation not requiring any
  * additional array allocations. Default initialCapacity is 10.
  */
-public expect open class SparseArrayCompat<E> @JvmOverloads public constructor(
+public expect open class SparseArrayCompat<E> public constructor(
     initialCapacity: Int = 10
 ) {
     @JvmSynthetic // Hide from Java callers.
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt b/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt
index a3c602f..4b8c9d6 100644
--- a/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt
+++ b/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt
@@ -53,8 +53,6 @@
 // TODO(b/237405792): Default value for optional argument is required here to workaround Metalava's
 //  lack of support for expect / actual.
 @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
-// TODO(b/237405286): @JvmOverloads is redundant in this actual, but is necessary here to workaround
-//  Metalava's lack of support for expect / actual.
 @JvmOverloads public actual constructor(initialCapacity: Int = 10) : Cloneable {
     @JvmSynthetic // Hide from Java callers.
     @JvmField
@@ -255,4 +253,4 @@
      * itself as a value, the string "(this Map)" will appear in its place.
      */
     actual override fun toString(): String = commonToString()
-}
\ No newline at end of file
+}
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 98f267f..2482074 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -15,8 +15,9 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -24,101 +25,111 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
+    if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
-                implementation("androidx.compose.runtime:runtime:1.2.1")
-                implementation("androidx.compose.ui:ui:1.2.1")
-                implementation("androidx.compose.ui:ui-unit:1.2.1")
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+        api("androidx.annotation:annotation:1.1.0")
+
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation("androidx.compose.ui:ui:1.2.1")
+        implementation("androidx.compose.ui:ui-unit:1.2.1")
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+        implementation(libs.kotlinStdlib)
+        api(libs.kotlinCoroutinesCore)
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.kotlinCoroutinesCore)
+
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(project(":compose:animation:animation"))
+        androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+        androidTestImplementation(project(":compose:test-utils"))
+
+        lintPublish project(":compose:animation:animation-core-lint")
+
+        samples(project(":compose:animation:animation-core:animation-core-samples"))
+    }
+}
+
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+
+            jvmMain {
+                dependencies {
+                    implementation(libs.kotlinStdlib)
+                    api(libs.kotlinCoroutinesCore)
+                }
+            }
+
+            commonMain.dependencies {
+                implementation(project(":compose:runtime:runtime"))
+                implementation(project(":compose:ui:ui"))
+                implementation(project(":compose:ui:ui-unit"))
+                implementation(project(":compose:ui:ui-util"))
                 implementation(libs.kotlinStdlibCommon)
                 api(libs.kotlinCoroutinesCore)
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-                implementation(libs.kotlinStdlib)
-                api(libs.kotlinCoroutinesCore)
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                api("androidx.annotation:annotation:1.1.0")
-                implementation(libs.kotlinStdlib)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
+            androidMain {
                 dependencies {
+                    api("androidx.annotation:annotation:1.1.0")
                     implementation(libs.kotlinStdlib)
-                    implementation(project(":compose:runtime:runtime"))
-                    implementation(project(":compose:ui:ui"))
-                    implementation(project(":compose:ui:ui-unit"))
-                    implementation(project(":compose:ui:ui-util"))
                 }
             }
-        }
-
-        jvmTest {
-            dependencies {
+            desktopMain {
+                dependencies {
+                    implementation(libs.kotlinStdlib)
+                }
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.testCore)
-                implementation(libs.junit)
-                implementation(project(":compose:animation:animation"))
-                implementation("androidx.compose.ui:ui-test-junit4:1.2.1")
-                implementation(project(":compose:test-utils"))
-            }
-        }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
                 implementation(libs.junit)
                 implementation(libs.truth)
                 implementation(libs.kotlinCoroutinesCore)
             }
-        }
 
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
+            androidAndroidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.testCore)
+                implementation(libs.junit)
+                implementation(project(":compose:animation:animation"))
+                implementation(project(":compose:ui:ui-test-junit4"))
+                implementation(project(":compose:test-utils"))
             }
         }
     }
-}
-
-dependencies {
-    lintPublish project(":compose:animation:animation-core-lint")
+    dependencies {
+        samples(project(":compose:animation:animation-core:animation-core-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/animation/animation-graphics/build.gradle b/compose/animation/animation-graphics/build.gradle
index f80a7a0..c6597a7 100644
--- a/compose/animation/animation-graphics/build.gradle
+++ b/compose/animation/animation-graphics/build.gradle
@@ -15,7 +15,7 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
@@ -25,106 +25,98 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api("androidx.annotation:annotation:1.1.0")
+        api(project(":compose:animation:animation"))
+        api("androidx.compose.foundation:foundation-layout:1.2.1")
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api("androidx.compose.ui:ui:1.2.1")
+        api("androidx.compose.ui:ui-geometry:1.2.1")
+
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+        implementation(libs.kotlinStdlibCommon)
+        implementation("androidx.core:core-ktx:1.5.0")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+
+        androidTestImplementation("androidx.compose.foundation:foundation:1.2.1")
+        androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+
+        samples(project(":compose:animation:animation-graphics:animation-graphics-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
                 api(project(":compose:animation:animation"))
-                api("androidx.compose.foundation:foundation-layout:1.2.1")
-                api("androidx.compose.runtime:runtime:1.2.1")
-                api("androidx.compose.ui:ui:1.2.1")
-                api("androidx.compose.ui:ui-geometry:1.2.1")
+                api(project(":compose:foundation:foundation-layout"))
+                api(project(":compose:runtime:runtime"))
+                api(project(":compose:ui:ui"))
+                api(project(":compose:ui:ui-geometry"))
 
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:ui:ui-util"))
             }
-        }
-        androidMain.dependencies {
-            api("androidx.annotation:annotation:1.1.0")
-            implementation("androidx.core:core-ktx:1.5.0")
-        }
 
-        commonTest {
-            dependencies {
+            androidMain.dependencies {
+                api("androidx.annotation:annotation:1.1.0")
+                implementation("androidx.core:core-ktx:1.5.0")
             }
-        }
 
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-                    api(project(":compose:foundation:foundation-layout"))
-                    api(project(":compose:runtime:runtime"))
-                    api(project(":compose:ui:ui"))
-                    api(project(":compose:ui:ui-geometry"))
-                    implementation(project(":compose:ui:ui-util"))
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
                 implementation(libs.junit)
                 implementation(libs.truth)
-                implementation("androidx.compose.foundation:foundation:1.2.1")
-                implementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+                implementation(project(":compose:foundation:foundation"))
+                implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":compose:test-utils"))
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
-            }
-        }
+    }
+    dependencies {
+        samples(project(":compose:animation:animation-graphics:animation-graphics-samples"))
     }
 }
 
diff --git a/compose/animation/animation/api/current.ignore b/compose/animation/animation/api/current.ignore
new file mode 100644
index 0000000..a02af1a
--- /dev/null
+++ b/compose/animation/animation/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedDeprecatedMethod: androidx.compose.animation.SplineBasedFloatDecayAnimationSpec_androidKt#splineBasedDecayDeprecated(androidx.compose.ui.unit.Density):
+    Removed deprecated method androidx.compose.animation.SplineBasedFloatDecayAnimationSpec_androidKt.splineBasedDecayDeprecated(androidx.compose.ui.unit.Density)
diff --git a/compose/animation/animation/api/current.txt b/compose/animation/animation/api/current.txt
index 6a4cd96..bb9d975 100644
--- a/compose/animation/animation/api/current.txt
+++ b/compose/animation/animation/api/current.txt
@@ -145,7 +145,7 @@
 
   public final class SplineBasedFloatDecayAnimationSpec_androidKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> rememberSplineBasedDecay();
-    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecayDeprecated(androidx.compose.ui.unit.Density density);
+    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecay(androidx.compose.ui.unit.Density density);
   }
 
   public final class TransitionKt {
diff --git a/compose/animation/animation/api/public_plus_experimental_current.txt b/compose/animation/animation/api/public_plus_experimental_current.txt
index ef9503c..5e6b679 100644
--- a/compose/animation/animation/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation/api/public_plus_experimental_current.txt
@@ -163,7 +163,7 @@
 
   public final class SplineBasedFloatDecayAnimationSpec_androidKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> rememberSplineBasedDecay();
-    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecayDeprecated(androidx.compose.ui.unit.Density density);
+    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecay(androidx.compose.ui.unit.Density density);
   }
 
   public final class TransitionKt {
diff --git a/compose/animation/animation/api/restricted_current.ignore b/compose/animation/animation/api/restricted_current.ignore
new file mode 100644
index 0000000..a02af1a
--- /dev/null
+++ b/compose/animation/animation/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedDeprecatedMethod: androidx.compose.animation.SplineBasedFloatDecayAnimationSpec_androidKt#splineBasedDecayDeprecated(androidx.compose.ui.unit.Density):
+    Removed deprecated method androidx.compose.animation.SplineBasedFloatDecayAnimationSpec_androidKt.splineBasedDecayDeprecated(androidx.compose.ui.unit.Density)
diff --git a/compose/animation/animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
index 6a4cd96..bb9d975 100644
--- a/compose/animation/animation/api/restricted_current.txt
+++ b/compose/animation/animation/api/restricted_current.txt
@@ -145,7 +145,7 @@
 
   public final class SplineBasedFloatDecayAnimationSpec_androidKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> rememberSplineBasedDecay();
-    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecayDeprecated(androidx.compose.ui.unit.Density density);
+    method @Deprecated public static <T> androidx.compose.animation.core.DecayAnimationSpec<T> splineBasedDecay(androidx.compose.ui.unit.Density density);
   }
 
   public final class TransitionKt {
diff --git a/compose/animation/animation/build.gradle b/compose/animation/animation/build.gradle
index 822d468..8d6b39f 100644
--- a/compose/animation/animation/build.gradle
+++ b/compose/animation/animation/build.gradle
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,102 +25,99 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api("androidx.annotation:annotation:1.1.0")
+        api(project(":compose:animation:animation-core"))
+        api("androidx.compose.foundation:foundation-layout:1.2.1")
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api("androidx.compose.ui:ui:1.2.1")
+        api("androidx.compose.ui:ui-geometry:1.2.1")
+
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+        implementation(libs.kotlinStdlibCommon)
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+
+        androidTestImplementation("androidx.compose.foundation:foundation:1.2.1")
+        androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+
+        lintPublish project(":compose:animation:animation-lint")
+
+        samples(project(":compose:animation:animation:animation-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
                 api(project(":compose:animation:animation-core"))
-                api("androidx.compose.foundation:foundation-layout:1.2.1")
-                api("androidx.compose.runtime:runtime:1.2.1")
-                api("androidx.compose.ui:ui:1.2.1")
-                api("androidx.compose.ui:ui-geometry:1.2.1")
+                api(project(":compose:foundation:foundation-layout"))
+                api(project(":compose:runtime:runtime"))
+                api(project(":compose:ui:ui"))
+                api(project(":compose:ui:ui-geometry"))
 
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-
-                    api(project(":compose:foundation:foundation-layout"))
-                    api(project(":compose:runtime:runtime"))
-                    api(project(":compose:ui:ui"))
-                    api(project(":compose:ui:ui-geometry"))
-
-                    implementation(project(":compose:ui:ui-util"))
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        jvmTest {
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
                 implementation(libs.junit)
                 implementation(libs.truth)
-                implementation("androidx.compose.foundation:foundation:1.2.1")
-                implementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+                implementation(project(":compose:foundation:foundation"))
+                implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":compose:test-utils"))
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
     }
-}
-
-dependencies {
-    lintPublish project(":compose:animation:animation-lint")
+    dependencies {
+        samples(project(":compose:animation:animation:animation-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 6c98520..1844ce5 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -45,6 +45,7 @@
 import androidx.compose.animation.demos.lookahead.LookaheadWithIntrinsicsDemo
 import androidx.compose.animation.demos.lookahead.LookaheadWithMovableContentDemo
 import androidx.compose.animation.demos.lookahead.LookaheadWithSubcompose
+import androidx.compose.animation.demos.lookahead.LookaheadWithTabRowDemo
 import androidx.compose.animation.demos.lookahead.ScreenSizeChangeDemo
 import androidx.compose.animation.demos.singlevalue.SingleValueAnimationDemo
 import androidx.compose.animation.demos.statetransition.CrossfadeDemo
@@ -130,6 +131,9 @@
                 ComposableDemo("Lookahead With Disappearing Movable Content") {
                     LookaheadWithDisappearingMovableContentDemo()
                 },
+                ComposableDemo("Lookahead With Tab Row") {
+                    LookaheadWithTabRowDemo()
+                },
             )
         ),
         DemoCategory(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithTabRowDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithTabRowDemo.kt
new file mode 100644
index 0000000..c4cb2dd
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithTabRowDemo.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.animation.demos.lookahead
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
+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.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.ScrollableTabRow
+import androidx.compose.material.Tab
+import androidx.compose.material.TabPosition
+import androidx.compose.material.TabRow
+import androidx.compose.material.TabRowDefaults
+import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.delay
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Preview
+@Composable
+fun LookaheadWithTabRowDemo() {
+    LookaheadScope {
+        val isWide by produceState(false) {
+            while (true) {
+                delay(5000)
+                value = !value
+            }
+        }
+        Column(
+            Modifier
+                .animateBounds(
+                    if (isWide) Modifier.fillMaxWidth() else Modifier.width(300.dp)
+                )
+                .fillMaxHeight()
+                .background(Color(0xFFfffbd0))
+        ) {
+            FancyTabs()
+            ScrollingTextTabs()
+            ScrollingFancyIndicatorContainerTabs()
+        }
+    }
+}
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun FancyTabs() {
+    var state by remember { mutableStateOf(0) }
+    val titles = listOf("TAB 1", "TAB 2", "TAB 3")
+    Column {
+        TabRow(
+            selectedTabIndex = state,
+            indicator = @Composable { tabPositions ->
+                TabRowDefaults.Indicator(
+                    Modifier.animateBounds(Modifier.tabIndicatorOffset(tabPositions[state]))
+                )
+            },
+        ) {
+            titles.forEachIndexed { index, title ->
+                FancyTab(title = title, onClick = { state = index }, selected = (index == state))
+            }
+        }
+        Text(
+            modifier = Modifier.align(Alignment.CenterHorizontally),
+            text = "Fancy tab ${state + 1} selected",
+            style = MaterialTheme.typography.body1
+        )
+    }
+}
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun FancyTab(title: String, onClick: () -> Unit, selected: Boolean) {
+    Tab(selected, onClick) {
+        Column(
+            Modifier
+                .padding(10.dp)
+                .height(50.dp)
+                .animateBounds(
+                    Modifier.fillMaxWidth()
+                ),
+            verticalArrangement = Arrangement.SpaceBetween
+        ) {
+            Box(
+                Modifier
+                    .size(10.dp)
+                    .align(Alignment.CenterHorizontally)
+                    .background(color = if (selected) Color.Red else Color.White)
+            )
+            Text(
+                text = title,
+                style = MaterialTheme.typography.body1,
+                modifier = Modifier.align(Alignment.CenterHorizontally)
+            )
+        }
+    }
+}
+
+@OptIn(ExperimentalComposeUiApi::class)
+@Composable
+fun ScrollingTextTabs() {
+    var state by remember { mutableStateOf(0) }
+    val titles = listOf(
+        "Tab 1",
+        "Tab 2",
+        "Tab 3 with lots of text",
+        "Tab 4",
+        "Tab 5",
+        "Tab 6 with lots of text",
+        "Tab 7",
+        "Tab 8",
+        "Tab 9 with lots of text",
+        "Tab 10"
+    )
+    Column {
+        ScrollableTabRow(selectedTabIndex = state) {
+            LookaheadScope {
+                titles.forEachIndexed { index, title ->
+                    Tab(
+                        selected = state == index,
+                        onClick = { state = index },
+                        text = { Text(title) }
+                    )
+                }
+            }
+        }
+        Text(
+            modifier = Modifier.align(Alignment.CenterHorizontally),
+            text = "Scrolling text tab ${state + 1} selected",
+            style = MaterialTheme.typography.body1
+        )
+    }
+}
+
+@Composable
+fun ScrollingFancyIndicatorContainerTabs() {
+    var state by remember { mutableStateOf(0) }
+    val titles = listOf(
+        "Tab 1",
+        "Tab 2",
+        "Tab 3 with lots of text",
+        "Tab 4",
+        "Tab 5",
+        "Tab 6 with lots of text",
+        "Tab 7",
+        "Tab 8",
+        "Tab 9 with lots of text",
+        "Tab 10"
+    )
+
+    // Reuse the default offset animation modifier, but use our own indicator
+    val indicator = @Composable { tabPositions: List<TabPosition> ->
+        FancyIndicator(Color.White, Modifier.tabIndicatorOffset(tabPositions[state]))
+    }
+
+    Column {
+        ScrollableTabRow(
+            selectedTabIndex = state,
+            indicator = indicator
+        ) {
+            titles.forEachIndexed { index, title ->
+                Tab(
+                    selected = state == index,
+                    onClick = { state = index },
+                    text = { Text(title) }
+                )
+            }
+        }
+        Text(
+            modifier = Modifier.align(Alignment.CenterHorizontally),
+            text = "Scrolling fancy transition tab ${state + 1} selected",
+            style = MaterialTheme.typography.body1
+        )
+    }
+}
+
+@Composable
+fun FancyIndicator(color: Color, modifier: Modifier = Modifier) {
+    // Draws a rounded rectangular with border around the Tab, with a 5.dp padding from the edges
+    // Color is passed in as a parameter [color]
+    Box(
+        modifier
+            .padding(5.dp)
+            .fillMaxSize()
+            .border(BorderStroke(2.dp, color), RoundedCornerShape(5.dp))
+    )
+}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
index 1845180..e9b56ea 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
@@ -69,7 +69,7 @@
         """,
         """
             @Composable
-            fun Test(%this%: Foo, %composer: Composer?, %changed: Int) {
+            fun Test(_context_receiver_0: Foo, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -83,7 +83,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                Test(%this%, %composer, updateChangedFlags(%changed or 0b0001))
+                Test(_context_receiver_0, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
         """
@@ -107,7 +107,7 @@
         """,
         """
             @Composable
-            fun A(%this%: Foo, %this%: Bar, %composer: Composer?, %changed: Int) {
+            fun A(_context_receiver_0: Foo, _context_receiver_1: Bar, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -121,11 +121,11 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                A(%this%, %this%, %composer, updateChangedFlags(%changed or 0b0001))
+                A(_context_receiver_0, _context_receiver_1, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
             @Composable
-            fun B(%this%: Foo, %this%: Bar, %this%: FooBar, %composer: Composer?, %changed: Int) {
+            fun B(_context_receiver_0: Foo, _context_receiver_1: Bar, _context_receiver_2: FooBar, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -139,7 +139,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                B(%this%, %this%, %this%, %composer, updateChangedFlags(%changed or 0b0001))
+                B(_context_receiver_0, _context_receiver_1, _context_receiver_2, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
         """
@@ -163,7 +163,7 @@
         """,
         """
             @Composable
-            fun String.A(%this%: Foo, %this%: Bar, %composer: Composer?, %changed: Int) {
+            fun String.A(_context_receiver_0: Foo, _context_receiver_1: Bar, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -177,11 +177,11 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                A(%this%, %this%, %composer, updateChangedFlags(%changed or 0b0001))
+                A(_context_receiver_0, _context_receiver_1, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
             @Composable
-            fun String.B(%this%: Foo, %this%: Bar, %this%: FooBar, %composer: Composer?, %changed: Int) {
+            fun String.B(_context_receiver_0: Foo, _context_receiver_1: Bar, _context_receiver_2: FooBar, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -195,7 +195,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                B(%this%, %this%, %this%, %composer, updateChangedFlags(%changed or 0b0001))
+                B(_context_receiver_0, _context_receiver_1, _context_receiver_2, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
         """
@@ -223,7 +223,7 @@
         """,
         """
             @Composable
-            fun A(%this%: Foo, %this%: Bar, a: Int, %composer: Composer?, %changed: Int, %default: Int) {
+            fun A(_context_receiver_0: Foo, _context_receiver_1: Bar, a: Int, %composer: Composer?, %changed: Int, %default: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -240,11 +240,11 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                A(%this%, %this%, a, %composer, updateChangedFlags(%changed or 0b0001), %default)
+                A(_context_receiver_0, _context_receiver_1, a, %composer, updateChangedFlags(%changed or 0b0001), %default)
               }
             }
             @Composable
-            fun B(%this%: Foo, %this%: Bar, %this%: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
+            fun B(_context_receiver_0: Foo, _context_receiver_1: Bar, _context_receiver_2: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -264,11 +264,11 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                B(%this%, %this%, %this%, a, b, c, %composer, updateChangedFlags(%changed or 0b0001), %default)
+                B(_context_receiver_0, _context_receiver_1, _context_receiver_2, a, b, c, %composer, updateChangedFlags(%changed or 0b0001), %default)
               }
             }
             @Composable
-            fun C(%this%: Foo, a: Int, bar: Bar?, %composer: Composer?, %changed: Int, %default: Int) {
+            fun C(_context_receiver_0: Foo, a: Int, bar: Bar?, %composer: Composer?, %changed: Int, %default: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(C):Test.kt")
               val %dirty = %changed
@@ -296,7 +296,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                C(%this%, a, bar, %composer, updateChangedFlags(%changed or 0b0001), %default)
+                C(_context_receiver_0, a, bar, %composer, updateChangedFlags(%changed or 0b0001), %default)
               }
             }
         """
@@ -316,7 +316,7 @@
         """,
         """
         @Composable
-        fun String.B(%this%: Foo, %this%: Bar, %this%: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
+        fun String.B(_context_receiver_0: Foo, _context_receiver_1: Bar, _context_receiver_2: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(B):Test.kt")
           if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -336,7 +336,7 @@
             %composer.skipToGroupEnd()
           }
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-            B(%this%, %this%, %this%, a, b, c, %composer, updateChangedFlags(%changed or 0b0001), %default)
+            B(_context_receiver_0, _context_receiver_1, _context_receiver_2, a, b, c, %composer, updateChangedFlags(%changed or 0b0001), %default)
           }
         }
         """
@@ -516,9 +516,9 @@
         """,
         """
             @Composable
-            fun Test(%this%: A, %this%: B, %this%: C, %this%: D, %this%: E, %this%: F, %this%: G, %this%: H, %this%: I, %this%: J, %this%: K, %this%: L, %composer: Composer?, %changed: Int, %changed1: Int) {
+            fun Test(_context_receiver_0: A, _context_receiver_1: B, _context_receiver_2: C, _context_receiver_3: D, _context_receiver_4: E, _context_receiver_5: F, _context_receiver_6: G, _context_receiver_7: H, _context_receiver_8: I, _context_receiver_9: J, _context_receiver_10: K, _context_receiver_11: L, %composer: Composer?, %changed: Int, %changed1: Int) {
               %composer = %composer.startRestartGroup(<>)
-              sourceInformation(%composer, "C(Test):Test.kt")
+              sourceInformation(%composer, "C(Test)P(!2,4,5,6,7,8,9,10,11):Test.kt")
               if (%changed and 0b0001 !== 0 || %changed1 and 0b0001 !== 0 || !%composer.skipping) {
                 if (isTraceInProgress()) {
                   traceEventStart(<>, %changed, %changed1, <>)
@@ -530,7 +530,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                Test(%this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %composer, updateChangedFlags(%changed or 0b0001), updateChangedFlags(%changed1))
+                Test(_context_receiver_0, _context_receiver_1, _context_receiver_2, _context_receiver_3, _context_receiver_4, _context_receiver_5, _context_receiver_6, _context_receiver_7, _context_receiver_8, _context_receiver_9, _context_receiver_10, _context_receiver_11, %composer, updateChangedFlags(%changed or 0b0001), updateChangedFlags(%changed1))
               }
             }
         """
@@ -551,7 +551,7 @@
         """
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
-            fun Test(%this%: Foo, a: String, b: Function3<String, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
+            fun Test(_context_receiver_0: Foo, a: String, b: Function3<String, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<b("yay...>:Test.kt")
               val %dirty = %changed
@@ -570,7 +570,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                Test(%this%, a, b, %composer, updateChangedFlags(%changed or 0b0001))
+                Test(_context_receiver_0, a, b, %composer, updateChangedFlags(%changed or 0b0001))
               }
             }
         """
@@ -629,14 +629,14 @@
               }
             }
             @Composable
-            fun Test(%this%: Foo, a: String?, b: Int, %composer: Composer?, %changed: Int, %default: Int) {
+            fun Test(_context_receiver_0: Foo, a: String?, b: Int, %composer: Composer?, %changed: Int, %default: Int) {
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
               if (%default and 0b0001 !== 0) {
                 %dirty = %dirty or 0b0110
               } else if (%changed and 0b1110 === 0) {
-                %dirty = %dirty or if (%composer.changed(%this%)) 0b0100 else 0b0010
+                %dirty = %dirty or if (%composer.changed(_context_receiver_0)) 0b0100 else 0b0010
               }
               if (%default and 0b0010 !== 0) {
                 %dirty = %dirty or 0b00110000
@@ -659,7 +659,7 @@
                   traceEventStart(<>, %changed, -1, <>)
                 }
                 val combineParams = a + b
-                if (%this%.someString == combineParams) {
+                if (_context_receiver_0.someString == combineParams) {
                   println("Same same")
                 }
                 if (isTraceInProgress()) {
@@ -669,7 +669,7 @@
                 %composer.skipToGroupEnd()
               }
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
-                Test(%this%, a, b, %composer, updateChangedFlags(%changed or 0b0001), %default)
+                Test(_context_receiver_0, a, b, %composer, updateChangedFlags(%changed or 0b0001), %default)
               }
             }
         """
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
index 5efb490..ad921b5 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
@@ -38,12 +38,12 @@
 
             @Composable
             fun Int.Foo(content: @Composable Int.(foo: String) -> Unit) {
-                content(<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
+                content<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>()<!>
             }
 
             @Composable
             fun Bar(content: @Composable Int.() -> Unit) {
-                content(<!NO_VALUE_FOR_PARAMETER!>)<!>
+                content<!NO_VALUE_FOR_PARAMETER!>()<!>
             }
         """
     )
@@ -208,10 +208,10 @@
             // otherwise correct file "red".
             @Composable fun Test(F: @Composable (x: Foo) -> Unit) {
                 // NOTE: constructor attributes and fn params get a "missing parameter" diagnostic
-                A(<!NO_VALUE_FOR_PARAMETER!>)<!>
+                A<!NO_VALUE_FOR_PARAMETER!>()<!>
 
                 // local
-                F(<!NO_VALUE_FOR_PARAMETER!>)<!>
+                F<!NO_VALUE_FOR_PARAMETER!>()<!>
 
                 val x = Foo(123)
 
@@ -271,7 +271,7 @@
 
             @Composable fun Test() {
                 <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>Foo()<!>
-                <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>Bar(<!NO_VALUE_FOR_PARAMETER!>)<!><!>
+                <!CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS!>Bar<!NO_VALUE_FOR_PARAMETER!>()<!><!>
             }
 
         """.trimIndent()
@@ -358,7 +358,7 @@
             }
 
             @Composable fun Test() {
-                Foo(abc=<!NO_VALUE_FOR_PARAMETER!>)<!>
+                Foo(<!NO_VALUE_FOR_PARAMETER!>abc=)<!>
 
                 // NOTE(lmr): even though there is NO diagnostic here, there *is* a parse
                 // error. This is intentional and done to mimic how kotlin handles function
@@ -502,7 +502,7 @@
 
             @Composable fun Test() {
                 ChildrenRequired2 {}
-                ChildrenRequired2(<!NO_VALUE_FOR_PARAMETER!>)<!>
+                ChildrenRequired2<!NO_VALUE_FOR_PARAMETER!>()<!>
 
                 ChildrenOptional3 {}
                 ChildrenOptional3()
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StaticExpressionDetectionTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StaticExpressionDetectionTests.kt
index 65d89e7..f1f0fd1 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StaticExpressionDetectionTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StaticExpressionDetectionTests.kt
@@ -20,7 +20,6 @@
 import androidx.compose.compiler.plugins.kotlin.lower.dumpSrc
 import org.intellij.lang.annotations.Language
 import org.jetbrains.kotlin.ir.declarations.IrFunction
-import org.jetbrains.kotlin.ir.util.nameForIrSerialization
 import org.junit.Assert.assertEquals
 import org.junit.Assert.fail
 import org.junit.Test
@@ -287,7 +286,7 @@
         )
         val compositionContextBody = irModule.files.last().declarations
             .filterIsInstance<IrFunction>()
-            .first { it.nameForIrSerialization.identifier == "CompositionContext" }
+            .first { it.name.identifier == "CompositionContext" }
             .dumpSrc()
             .replace('$', '%')
 
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
index 3239060..07aa897 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
@@ -286,4 +286,74 @@
             """
         )
     }
+
+    @Test
+    fun testOverrideComposableLambda() {
+        check(
+            """
+                import androidx.compose.runtime.Composable
+
+                class Impl : @Composable () -> Unit {
+                    @Composable
+                    override fun invoke() {}
+                }
+            """
+        )
+    }
+
+    @Test
+    fun testTransitiveOverrideComposableLambda() {
+        check(
+            """
+                import androidx.compose.runtime.Composable
+
+                interface ComposableFunction : @Composable () -> Unit
+
+                class Impl : ComposableFunction {
+                    @Composable
+                    override fun invoke() {}
+                }
+            """
+        )
+    }
+
+    @Test
+    fun testMissingOverrideComposableLambda() {
+        check(
+            """
+                import androidx.compose.runtime.Composable
+
+                class Impl : @Composable () -> Unit {
+                    <!CONFLICTING_OVERLOADS!>override fun invoke()<!> {}
+                }
+            """
+        )
+    }
+
+    @Test
+    fun testWrongOverrideLambda() {
+        check(
+            """
+                import androidx.compose.runtime.Composable
+
+                class Impl : () -> Unit {
+                    <!CONFLICTING_OVERLOADS!>@Composable override fun invoke()<!> {}
+                }
+            """
+        )
+    }
+
+    @Test
+    fun testMultipleOverrideLambda() {
+        check(
+            """
+                import androidx.compose.runtime.Composable
+
+                class Impl : () -> Unit, @Composable (Int) -> Unit {
+                    <!CONFLICTING_OVERLOADS!>@Composable override fun invoke()<!> {}
+                    @Composable override fun invoke(p0: Int) {}
+                }
+            """
+        )
+    }
 }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
index c0aad2e..2cc17dc 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
@@ -22,9 +22,11 @@
 import androidx.compose.compiler.plugins.kotlin.ComposeErrors.COMPOSABLE_SUSPEND_FUN
 import androidx.compose.compiler.plugins.kotlin.ComposeErrors.COMPOSABLE_VAR
 import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.builtins.isFunctionType
 import org.jetbrains.kotlin.builtins.isSuspendFunctionType
 import org.jetbrains.kotlin.container.StorageComponentContainer
 import org.jetbrains.kotlin.container.useInstance
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
 import org.jetbrains.kotlin.descriptors.Modality
@@ -41,6 +43,7 @@
 import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
 import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
 import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.typeUtil.supertypes
 import org.jetbrains.kotlin.util.OperatorNameConventions
 
 class ComposableDeclarationChecker : DeclarationChecker, StorageComponentContainerContributor {
@@ -79,7 +82,22 @@
         val hasComposableAnnotation = descriptor.hasComposableAnnotation()
         if (descriptor.overriddenDescriptors.isNotEmpty()) {
             val override = descriptor.overriddenDescriptors.first()
-            if (override.hasComposableAnnotation() != hasComposableAnnotation) {
+            val overrideFunctionIsComposable =
+                if (descriptor.isOperator && descriptor.name == OperatorNameConventions.INVOKE) {
+                    override.hasComposableAnnotation() || descriptor.let {
+                        val cls = descriptor.containingDeclaration as? ClassDescriptor
+                        cls?.run {
+                            defaultType.supertypes().any {
+                                it.isFunctionType &&
+                                    it.arguments.size == descriptor.arity + 1 &&
+                                    it.hasComposableAnnotation()
+                            }
+                        } ?: false
+                    }
+                } else {
+                    override.hasComposableAnnotation()
+                }
+            if (overrideFunctionIsComposable != hasComposableAnnotation) {
                 context.trace.report(
                     ComposeErrors.CONFLICTING_OVERLOADS.on(
                         declaration,
@@ -234,4 +252,9 @@
             context.trace.report(COMPOSABLE_VAR.on(name))
         }
     }
+
+    private val FunctionDescriptor.arity get(): Int =
+        if (extensionReceiverParameter != null) 1 else 0 +
+            contextReceiverParameters.size +
+            valueParameters.size
 }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
index 4629463..17c8e1b 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
@@ -41,7 +41,7 @@
 import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsGlobalDeclarationTable
 import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
-import org.jetbrains.kotlin.platform.js.isJs
+import org.jetbrains.kotlin.platform.isJs
 import org.jetbrains.kotlin.platform.jvm.isJvm
 
 class ComposeIrGenerationExtension(
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
index d0d3b5e..b7b2c89 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
@@ -208,7 +208,7 @@
     companion object {
         fun checkCompilerVersion(configuration: CompilerConfiguration): Boolean {
             try {
-                val KOTLIN_VERSION_EXPECTATION = "1.8.10"
+                val KOTLIN_VERSION_EXPECTATION = "1.8.20"
                 KotlinCompilerVersion.getVersion()?.let { version ->
                     val msgCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
                     val suppressKotlinVersionCheck = configuration.get(
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index 1896f67..9eb33b2 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -111,6 +111,7 @@
             9701 to "1.4.0-rc02",
             9701 to "1.5.0-alpha01",
             9801 to "1.5.0-alpha02",
+            9901 to "1.5.0-alpha03",
         )
 
         /**
@@ -123,7 +124,7 @@
          * The maven version string of this compiler. This string should be updated before/after every
          * release.
          */
-        const val compilerVersion: String = "1.5.0-alpha02"
+        const val compilerVersion: String = "1.4.6"
         private val minimumRuntimeVersion: String
             get() = runtimeVersionToMavenVersionTable[minimumRuntimeVersionInt] ?: "unknown"
     }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index e4f2e8a3..75033ec 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -152,7 +152,7 @@
 import org.jetbrains.kotlin.name.FqNameUnsafe
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.name.SpecialNames
-import org.jetbrains.kotlin.platform.js.isJs
+import org.jetbrains.kotlin.platform.isJs
 import org.jetbrains.kotlin.platform.jvm.isJvm
 import org.jetbrains.kotlin.util.OperatorNameConventions
 
@@ -3852,7 +3852,9 @@
                 for (param in function.valueParameters) {
                     val paramName = param.name.asString()
                     when {
-                        !paramName.startsWith('$') -> realValueParamCount++
+                        !paramName.startsWith('$') &&
+                            !paramName.startsWith("_context_receiver_") ->
+                            realValueParamCount++
                         paramName == KtxNameConventions.COMPOSER_PARAMETER.identifier ->
                             composerParameter = param
                         paramName.startsWith(KtxNameConventions.DEFAULT_PARAMETER.identifier) ->
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index b4d3b2e..3a8ba5a 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -92,7 +92,7 @@
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
 import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.platform.js.isJs
+import org.jetbrains.kotlin.platform.isJs
 import org.jetbrains.kotlin.platform.jvm.isJvm
 
 private class CaptureCollector {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
index 006279c..0980e11b 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
@@ -81,7 +81,7 @@
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.load.java.JvmAbi
 import org.jetbrains.kotlin.name.StandardClassIds
-import org.jetbrains.kotlin.platform.js.isJs
+import org.jetbrains.kotlin.platform.isJs
 import org.jetbrains.kotlin.platform.jvm.isJvm
 import org.jetbrains.kotlin.resolve.DescriptorUtils
 import org.jetbrains.kotlin.util.OperatorNameConventions
diff --git a/compose/desktop/desktop/build.gradle b/compose/desktop/desktop/build.gradle
index 4d4e9a2..a8baf7a 100644
--- a/compose/desktop/desktop/build.gradle
+++ b/compose/desktop/desktop/build.gradle
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-
-import androidx.build.KmpPlatformsKt
 import androidx.build.LibraryType
 import androidx.build.RunApiTasks
 import androidx.build.BuildOnServerKt
@@ -28,55 +26,41 @@
     id("kotlin-multiplatform")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
-
 dependencies {
 }
 
 kotlin {
-    if (desktopEnabled) {
-        jvm() {
-            withJava()
-        }
+    jvm() {
+        withJava()
     }
 
-    if (desktopEnabled) {
-        sourceSets {
-            commonMain.dependencies {
-                implementation(libs.kotlinStdlibCommon)
-                implementation(project(":compose:ui:ui-util"))
-                api(project(":compose:foundation:foundation"))
-                api(project(":compose:material:material"))
-                api(project(":compose:runtime:runtime"))
-                api(project(":compose:ui:ui"))
-                api(project(":compose:ui:ui-tooling-preview"))
-            }
-
-            jvmMain.dependencies {
-                implementation(libs.kotlinStdlib)
-                implementation(libs.kotlinStdlibJdk8)
-                implementation(libs.kotlinCoroutinesCore)
-            }
-
-            jvmTest {
-                resources.srcDirs += new File(SupportConfigKt.getExternalProjectPath(project), "noto-fonts/other/")
-                resources.srcDirs += "src/jvmTest/res"
-                dependencies {
-                    implementation(libs.kotlinCoroutinesTest)
-                    implementation(libs.skikoCurrentOs)
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                    implementation(libs.junit)
-                    implementation(libs.truth)
-                }
-            }
+    sourceSets {
+        commonMain.dependencies {
+            implementation(libs.kotlinStdlibCommon)
+            implementation(project(":compose:ui:ui-util"))
+            api(project(":compose:foundation:foundation"))
+            api(project(":compose:material:material"))
+            api(project(":compose:runtime:runtime"))
+            api(project(":compose:ui:ui"))
+            api(project(":compose:ui:ui-tooling-preview"))
         }
-    }
-}
 
-if (!desktopEnabled) {
-    kotlin {
-        jvm("disabled") {
-            withJava()
+        jvmMain.dependencies {
+            implementation(libs.kotlinStdlib)
+            implementation(libs.kotlinStdlibJdk8)
+            implementation(libs.kotlinCoroutinesCore)
+        }
+
+        jvmTest {
+            resources.srcDirs += new File(SupportConfigKt.getExternalProjectPath(project), "noto-fonts/other/")
+            resources.srcDirs += "src/jvmTest/res"
+            dependencies {
+                implementation(libs.kotlinCoroutinesTest)
+                implementation(libs.skikoCurrentOs)
+                implementation(project(":compose:ui:ui-test-junit4"))
+                implementation(libs.junit)
+                implementation(libs.truth)
+            }
         }
     }
 }
@@ -90,10 +74,8 @@
     }
 }
 
-if (desktopEnabled) {
-    tasks.findByName("jvmTest").configure {
-        systemProperties["GOLDEN_PATH"] = getGoldenPath(project).toString()
-    }
+tasks.findByName("jvmTest").configure {
+    systemProperties["GOLDEN_PATH"] = getGoldenPath(project).toString()
 }
 
 androidx {
@@ -145,6 +127,4 @@
     }
 }
 
-if (desktopEnabled) {
-    BuildOnServerKt.addToBuildOnServer(project, "${project.path}:jvmJar")
-}
+BuildOnServerKt.addToBuildOnServer(project, "${project.path}:jvmJar")
diff --git a/compose/desktop/desktop/samples/build.gradle b/compose/desktop/desktop/samples/build.gradle
index 7502716..76b09be 100644
--- a/compose/desktop/desktop/samples/build.gradle
+++ b/compose/desktop/desktop/samples/build.gradle
@@ -15,105 +15,94 @@
  */
 
 import androidx.build.BuildOnServerKt
-import androidx.build.KmpPlatformsKt
 import androidx.build.SupportConfigKt
 
 plugins {
     id("AndroidXPlugin")
-    id("java")
     id("AndroidXComposePlugin")
     id("kotlin-multiplatform")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
-
-if (desktopEnabled) {
-    kotlin {
-        jvm()
-
-        sourceSets {
-            jvmMain {
-                resources.srcDirs += new File(SupportConfigKt.getExternalProjectPath(project), "noto-fonts/other/")
-                resources.srcDirs += "src/jvmMain/res"
-            }
-
-            jvmMain.dependencies {
-                implementation(libs.skikoCurrentOs)
-                implementation(project(":compose:desktop:desktop"))
-            }
-        }
-    }
-
-    task run1(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.example1.Main_jvmKt"
-        systemProperty("skiko.fps.enabled", "true")
-        def compilation = kotlin.jvm().compilations["main"]
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task run2(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.example2.Main_jvmKt"
-        def compilation = kotlin.jvm().compilations["main"]
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task run3(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.popupexample.Main_jvmKt"
-        def compilation = kotlin.jvm().compilations["main"]
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task run4(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.swingexample.Main_jvmKt"
-        def compilation = kotlin.jvm().compilations["main"]
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task runVsync(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.vsynctest.Main_jvmKt"
-        jvmArgs("-verbose:gc")
-        def compilation = kotlin.jvm().compilations["main"]
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task runWindowApi(type: JavaExec) {
-        dependsOn(":compose:desktop:desktop:jar")
-        main = "androidx.compose.desktop.examples.windowapi.Main_jvmKt"
-        def compilation = kotlin.jvm().compilations["main"]
-        systemProperty("skiko.rendering.laf.global", "true")
-        systemProperty("skiko.rendering.useScreenMenuBar", "true")
-        classpath =
-                compilation.output.allOutputs +
-                        compilation.runtimeDependencyFiles
-    }
-
-    task run {
-        dependsOn("run1")
-    }
-
-
-    BuildOnServerKt.addToBuildOnServer(project, "${project.path}:jvmJar")
+dependencies {
 }
 
-if (!desktopEnabled) {
-    kotlin {
-        jvm("disabled") {
-            withJava()
+kotlin {
+    jvm()
+
+    sourceSets {
+        jvmMain {
+            resources.srcDirs += new File(SupportConfigKt.getExternalProjectPath(project), "noto-fonts/other/")
+            resources.srcDirs += "src/jvmMain/res"
+        }
+
+        jvmMain.dependencies {
+            implementation(libs.skikoCurrentOs)
+            implementation(project(":compose:desktop:desktop"))
         }
     }
 }
+
+task run1(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.example1.Main_jvmKt"
+    systemProperty("skiko.fps.enabled", "true")
+    def compilation = kotlin.jvm().compilations["main"]
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task run2(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.example2.Main_jvmKt"
+    def compilation = kotlin.jvm().compilations["main"]
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task run3(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.popupexample.Main_jvmKt"
+    def compilation = kotlin.jvm().compilations["main"]
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task run4(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.swingexample.Main_jvmKt"
+    def compilation = kotlin.jvm().compilations["main"]
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task runVsync(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.vsynctest.Main_jvmKt"
+    jvmArgs("-verbose:gc")
+    def compilation = kotlin.jvm().compilations["main"]
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task runWindowApi(type: JavaExec) {
+    dependsOn(":compose:desktop:desktop:jar")
+    main = "androidx.compose.desktop.examples.windowapi.Main_jvmKt"
+    def compilation = kotlin.jvm().compilations["main"]
+    systemProperty("skiko.rendering.laf.global", "true")
+    systemProperty("skiko.rendering.useScreenMenuBar", "true")
+    classpath =
+        compilation.output.allOutputs +
+        compilation.runtimeDependencyFiles
+}
+
+task run {
+    dependsOn("run1")
+}
+
+
+BuildOnServerKt.addToBuildOnServer(project, "${project.path}:jvmJar")
diff --git a/compose/desktop/desktop/samples/src/jvmMain/disabled/Empty.kt b/compose/desktop/desktop/samples/src/jvmMain/disabled/Empty.kt
deleted file mode 100644
index 0c32401..0000000
--- a/compose/desktop/desktop/samples/src/jvmMain/disabled/Empty.kt
+++ /dev/null
@@ -1 +0,0 @@
-// Give Kotlin a placeholder file to compile when this project is disabled.
\ No newline at end of file
diff --git a/compose/desktop/desktop/src/disabled/Empty.kt b/compose/desktop/desktop/src/disabled/Empty.kt
deleted file mode 100644
index 0c32401..0000000
--- a/compose/desktop/desktop/src/disabled/Empty.kt
+++ /dev/null
@@ -1 +0,0 @@
-// Give Kotlin a placeholder file to compile when this project is disabled.
\ No newline at end of file
diff --git a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
index 741ffe0..57c57c0 100644
--- a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
@@ -115,8 +115,8 @@
   }
 
   public final class FlowLayoutKt {
-    method @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 int maxItemsInEachColumn, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @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 int maxItemsInEachRow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static inline 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 int maxItemsInEachColumn, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.foundation.layout.ExperimentalLayoutApi @androidx.compose.runtime.Composable public static inline 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 int maxItemsInEachRow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class IntrinsicKt {
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 4aae0e6..03cdfb3 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -114,6 +114,11 @@
     method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier weight(androidx.compose.ui.Modifier, float weight, optional boolean fill);
   }
 
+  public final class FlowLayoutKt {
+    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);
+  }
+
   public final class IntrinsicKt {
     method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier height(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
     method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier requiredHeight(androidx.compose.ui.Modifier, androidx.compose.foundation.layout.IntrinsicSize intrinsicSize);
diff --git a/compose/foundation/foundation-layout/build.gradle b/compose/foundation/foundation-layout/build.gradle
index 1e3b202..a754486 100644
--- a/compose/foundation/foundation-layout/build.gradle
+++ b/compose/foundation/foundation-layout/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,65 +24,94 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+
+        api("androidx.annotation:annotation:1.1.0")
+        api(project(":compose:ui:ui"))
+        api("androidx.compose.ui:ui-unit:1.2.1")
+
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+        implementation("androidx.core:core:1.7.0")
+        implementation("androidx.compose.animation:animation-core:1.2.1")
+        implementation(libs.kotlinStdlibCommon)
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation("androidx.activity:activity-compose:1.3.1")
+        // old version of common-java8 conflicts with newer version, because both have
+        // DefaultLifecycleEventObserver.
+        // Outside of androidx this is resolved via constraint added to lifecycle-common,
+        // but it doesn't work in androidx.
+        // See aosp/1804059
+        androidTestImplementation("androidx.lifecycle:lifecycle-common-java8:2.5.1")
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+
+        samples(project(":compose:foundation:foundation-layout:foundation-layout-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
                 api(project(":compose:ui:ui"))
-                implementation("androidx.compose.runtime:runtime:1.2.1")
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:runtime:runtime"))
+                implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
                 implementation("androidx.core:core:1.7.0")
                 implementation("androidx.compose.animation:animation-core:1.2.1")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-
-                    implementation(project(":compose:runtime:runtime"))
-                    implementation(project(":compose:ui:ui-util"))
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        jvmTest {
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:foundation:foundation"))
-                implementation("androidx.compose.ui:ui-test-junit4:1.2.1")
+                implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":compose:test-utils"))
                 implementation("androidx.activity:activity-compose:1.3.1")
 
@@ -91,26 +121,9 @@
                 implementation(libs.truth)
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
+    }
+    dependencies {
+        samples(project(":compose:foundation:foundation-layout:foundation-layout-samples"))
     }
 }
 
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 ded1da7..9ec9beb 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
@@ -51,7 +51,7 @@
  */
 @Composable
 @ExperimentalLayoutApi
-fun FlowRow(
+inline fun FlowRow(
     modifier: Modifier = Modifier,
     horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
     verticalArrangement: Arrangement.Vertical = Arrangement.Top,
@@ -101,7 +101,7 @@
  */
 @Composable
 @ExperimentalLayoutApi
-fun FlowColumn(
+inline fun FlowColumn(
     modifier: Modifier = Modifier,
     verticalArrangement: Arrangement.Vertical = Arrangement.Top,
     horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
@@ -136,8 +136,9 @@
         }
     }
 
+@PublishedApi
 @Composable
-private fun rowMeasurementHelper(
+internal fun rowMeasurementHelper(
     horizontalArrangement: Arrangement.Horizontal,
     verticalArrangement: Arrangement.Vertical,
     maxItemsInMainAxis: Int,
@@ -156,8 +157,9 @@
     }
 }
 
+@PublishedApi
 @Composable
-private fun columnMeasurementHelper(
+internal fun columnMeasurementHelper(
     verticalArrangement: Arrangement.Vertical,
     horizontalArrangement: Arrangement.Horizontal,
     maxItemsInMainAxis: Int,
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 486f141..f1eb981 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -1291,8 +1291,12 @@
 
 package androidx.compose.foundation.text2 {
 
+  public final class BasicSecureTextFieldKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicSecureTextField(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,java.lang.Boolean>? onSubmit, optional int imeAction, optional int textObfuscationMode, optional int keyboardType, optional boolean enabled, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+  }
+
   public final class BasicTextField2Kt {
-    method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicTextField2(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional int minLines, optional int maxLines, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void BasicTextField2(androidx.compose.foundation.text2.input.TextFieldState state, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.foundation.text2.input.TextEditFilter? filter, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional androidx.compose.foundation.text2.input.TextFieldLineLimits lineLimits, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.foundation.text2.input.CodepointTransformation? codepointTransformation, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
   }
 
 }
@@ -1303,51 +1307,98 @@
     method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter allCaps(androidx.compose.foundation.text2.input.TextEditFilter.Companion, androidx.compose.ui.text.intl.Locale locale);
   }
 
+  @androidx.compose.foundation.ExperimentalFoundationApi public fun interface CodepointTransformation {
+    method public int transform(int codepointIndex, int codepoint);
+    field public static final androidx.compose.foundation.text2.input.CodepointTransformation.Companion Companion;
+  }
+
+  public static final class CodepointTransformation.Companion {
+    method public androidx.compose.foundation.text2.input.CodepointTransformation getNone();
+    property public final androidx.compose.foundation.text2.input.CodepointTransformation None;
+  }
+
+  public final class CodepointTransformationKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.CodepointTransformation mask(androidx.compose.foundation.text2.input.CodepointTransformation.Companion, char character);
+  }
+
   public final class MaxLengthFilterKt {
     method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInChars(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
     method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter maxLengthInCodepoints(androidx.compose.foundation.text2.input.TextEditFilter.Companion, int maxLength);
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi public class MutableTextFieldValue implements java.lang.Appendable java.lang.CharSequence {
-    method public Appendable append(char char);
+  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface TextEditFilter {
+    method public void filter(androidx.compose.foundation.text2.input.TextFieldCharSequence originalValue, androidx.compose.foundation.text2.input.TextFieldBufferWithSelection valueWithChanges);
+    method public default androidx.compose.foundation.text.KeyboardOptions? getKeyboardOptions();
+    property public default androidx.compose.foundation.text.KeyboardOptions? keyboardOptions;
+    field public static final androidx.compose.foundation.text2.input.TextEditFilter.Companion Companion;
+  }
+
+  public static final class TextEditFilter.Companion {
+  }
+
+  public final class TextEditFilterKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter then(androidx.compose.foundation.text2.input.TextEditFilter, androidx.compose.foundation.text2.input.TextEditFilter next, optional androidx.compose.foundation.text.KeyboardOptions? keyboardOptions);
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi public abstract sealed class TextEditResult {
+  }
+
+  public final class TextEditResultKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAfterLastChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldBuffer);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCharAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeCodepointAt(androidx.compose.foundation.text2.input.TextFieldBuffer, int index);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult placeCursorBeforeFirstChange(androidx.compose.foundation.text2.input.TextFieldBuffer);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAll(androidx.compose.foundation.text2.input.TextFieldBuffer);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectAllChanges(androidx.compose.foundation.text2.input.TextFieldBuffer);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCharsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextEditResult selectCodepointsIn(androidx.compose.foundation.text2.input.TextFieldBuffer, long range);
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi public class TextFieldBuffer implements java.lang.Appendable java.lang.CharSequence {
     method public Appendable append(CharSequence? text);
     method public Appendable append(CharSequence? text, int start, int end);
+    method public Appendable append(char char);
     method public operator char get(int index);
-    method public final androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList getChanges();
+    method public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList getChanges();
     method public final int getCodepointLength();
     method public int getLength();
     method @CallSuper protected void onTextWillChange(long rangeToBeReplaced, int newLength);
     method public final void replace(int start, int end, String text);
     method public CharSequence subSequence(int startIndex, int endIndex);
-    property public final androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList changes;
+    property public final androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList changes;
     property public final int codepointLength;
     property public int length;
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi public static interface MutableTextFieldValue.ChangeList {
+  @androidx.compose.foundation.ExperimentalFoundationApi public static interface TextFieldBuffer.ChangeList {
     method public int getChangeCount();
     method public long getOriginalRange(int changeIndex);
     method public long getRange(int changeIndex);
     property public abstract int changeCount;
   }
 
-  public final class MutableTextFieldValueKt {
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static void delete(androidx.compose.foundation.text2.input.MutableTextFieldValue, int start, int end);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChange(androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChangeReversed(androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static void insert(androidx.compose.foundation.text2.input.MutableTextFieldValue, int index, String text);
+  public final class TextFieldBufferKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static void delete(androidx.compose.foundation.text2.input.TextFieldBuffer, int start, int end);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChange(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static inline void forEachChangeReversed(androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.TextRange,? super androidx.compose.ui.text.TextRange,kotlin.Unit> block);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static void insert(androidx.compose.foundation.text2.input.TextFieldBuffer, int index, String text);
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi public final class MutableTextFieldValueWithSelection extends androidx.compose.foundation.text2.input.MutableTextFieldValue {
+  @androidx.compose.foundation.ExperimentalFoundationApi public final class TextFieldBufferWithSelection extends androidx.compose.foundation.text2.input.TextFieldBuffer {
     method public boolean getHasSelection();
     method public long getSelectionInChars();
     method public long getSelectionInCodepoints();
+    method public void placeCursorAfterCharAt(int index);
+    method public void placeCursorAfterCodepointAt(int index);
     method public void placeCursorAfterLastChange();
     method public void placeCursorAtEnd();
     method public void placeCursorBeforeCharAt(int index);
     method public void placeCursorBeforeCodepointAt(int index);
     method public void placeCursorBeforeFirstChange();
-    method public void resetTo(androidx.compose.ui.text.input.TextFieldValue value);
+    method public void revertAllChanges();
     method public void selectAll();
     method public void selectAllChanges();
     method public void selectCharsIn(long range);
@@ -1357,38 +1408,46 @@
     property public final long selectionInCodepoints;
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public fun interface TextEditFilter {
-    method public void filter(androidx.compose.ui.text.input.TextFieldValue oldState, androidx.compose.foundation.text2.input.MutableTextFieldValueWithSelection newState);
-    field public static final androidx.compose.foundation.text2.input.TextEditFilter.Companion Companion;
+  @androidx.compose.foundation.ExperimentalFoundationApi public sealed interface TextFieldCharSequence extends java.lang.CharSequence {
+    method public boolean contentEquals(CharSequence other);
+    method public boolean equals(Object? other);
+    method public androidx.compose.ui.text.TextRange? getCompositionInChars();
+    method public long getSelectionInChars();
+    method public int hashCode();
+    property public abstract androidx.compose.ui.text.TextRange? compositionInChars;
+    property public abstract long selectionInChars;
   }
 
-  public static final class TextEditFilter.Companion {
+  public final class TextFieldCharSequenceKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldCharSequence TextFieldCharSequence(optional String text, optional long selection);
   }
 
-  public final class TextEditFilterKt {
-    method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public static androidx.compose.foundation.text2.input.TextEditFilter then(androidx.compose.foundation.text2.input.TextEditFilter, androidx.compose.foundation.text2.input.TextEditFilter next);
+  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface TextFieldLineLimits {
+    field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.Companion Companion;
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi public abstract sealed class TextFieldEditResult {
+  public static final class TextFieldLineLimits.Companion {
+    method public androidx.compose.foundation.text2.input.TextFieldLineLimits getDefault();
+    property public final androidx.compose.foundation.text2.input.TextFieldLineLimits Default;
   }
 
-  public final class TextFieldEditResultKt {
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult placeCursorAfterLastChange(androidx.compose.foundation.text2.input.MutableTextFieldValue);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult placeCursorAtEnd(androidx.compose.foundation.text2.input.MutableTextFieldValue);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult placeCursorBeforeCharAt(androidx.compose.foundation.text2.input.MutableTextFieldValue, int index);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult placeCursorBeforeCodepointAt(androidx.compose.foundation.text2.input.MutableTextFieldValue, int index);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult placeCursorBeforeFirstChange(androidx.compose.foundation.text2.input.MutableTextFieldValue);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult selectAll(androidx.compose.foundation.text2.input.MutableTextFieldValue);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult selectAllChanges(androidx.compose.foundation.text2.input.MutableTextFieldValue);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult selectCharsIn(androidx.compose.foundation.text2.input.MutableTextFieldValue, long range);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.foundation.text2.input.TextFieldEditResult selectCodepointsIn(androidx.compose.foundation.text2.input.MutableTextFieldValue, long range);
+  @androidx.compose.runtime.Immutable public static final class TextFieldLineLimits.MultiLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+    ctor public TextFieldLineLimits.MultiLine(optional int minHeightInLines, optional int maxHeightInLines);
+    method public int getMaxHeightInLines();
+    method public int getMinHeightInLines();
+    property public final int maxHeightInLines;
+    property public final int minHeightInLines;
   }
 
-  @androidx.compose.foundation.ExperimentalFoundationApi public final class TextFieldState {
-    ctor public TextFieldState(optional androidx.compose.ui.text.input.TextFieldValue initialValue);
-    method public inline void edit(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.text2.input.MutableTextFieldValue,? extends androidx.compose.foundation.text2.input.TextFieldEditResult> block);
-    method public androidx.compose.ui.text.input.TextFieldValue getValue();
-    property public final androidx.compose.ui.text.input.TextFieldValue value;
+  public static final class TextFieldLineLimits.SingleLine implements androidx.compose.foundation.text2.input.TextFieldLineLimits {
+    field public static final androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine INSTANCE;
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class TextFieldState {
+    ctor public TextFieldState(optional String initialText, optional long initialSelectionInChars);
+    method public inline void edit(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.text2.input.TextFieldBuffer,? extends androidx.compose.foundation.text2.input.TextEditResult> block);
+    method public androidx.compose.foundation.text2.input.TextFieldCharSequence getText();
+    property public final androidx.compose.foundation.text2.input.TextFieldCharSequence text;
   }
 
   public static final class TextFieldState.Saver implements androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.text2.input.TextFieldState,java.lang.Object> {
@@ -1398,9 +1457,26 @@
   }
 
   public final class TextFieldStateKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend Object? forEachTextValue(androidx.compose.foundation.text2.input.TextFieldState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.text2.input.TextFieldCharSequence,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<?>);
     method @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static androidx.compose.foundation.text2.input.TextFieldState rememberTextFieldState();
     method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndPlaceCursorAtEnd(androidx.compose.foundation.text2.input.TextFieldState, String text);
     method @androidx.compose.foundation.ExperimentalFoundationApi public static void setTextAndSelectAll(androidx.compose.foundation.text2.input.TextFieldState, String text);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static kotlinx.coroutines.flow.Flow<androidx.compose.foundation.text2.input.TextFieldCharSequence> textAsFlow(androidx.compose.foundation.text2.input.TextFieldState);
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi @kotlin.jvm.JvmInline public final value class TextObfuscationMode {
+    method public int getValue();
+    property public final int value;
+    field public static final androidx.compose.foundation.text2.input.TextObfuscationMode.Companion Companion;
+  }
+
+  public static final class TextObfuscationMode.Companion {
+    method public int getHidden();
+    method public int getRevealLastTyped();
+    method public int getVisible();
+    property public final int Hidden;
+    property public final int RevealLastTyped;
+    property public final int Visible;
   }
 
 }
diff --git a/compose/foundation/foundation/build.gradle b/compose/foundation/foundation/build.gradle
index ecd53ce..6b0f5ef 100644
--- a/compose/foundation/foundation/build.gradle
+++ b/compose/foundation/foundation/build.gradle
@@ -15,8 +15,9 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -25,74 +26,116 @@
     id("AndroidXPaparazziPlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        api("androidx.annotation:annotation:1.1.0")
+        api("androidx.compose.animation:animation:1.2.1")
+        api(project(":compose:runtime:runtime"))
+        api(project(":compose:ui:ui"))
+
+        implementation(libs.kotlinStdlibCommon)
+        implementation(project(":compose:foundation:foundation-layout"))
+        implementation(project(':emoji2:emoji2'))
+        implementation("androidx.core:core:1.9.0")
+        implementation("androidx.compose.ui:ui-graphics:1.2.1")
+        implementation("androidx.compose.ui:ui-text:1.2.1")
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+
+        testImplementation(project(":compose:test-utils"))
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.kotlinCoroutinesTest)
+        testImplementation(libs.kotlinTest)
+        testImplementation(libs.mockitoCore4)
+        testImplementation(libs.kotlinReflect)
+        testImplementation(libs.mockitoKotlin4)
+
+        testImplementation(project(":constraintlayout:constraintlayout-compose"))
+
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":internal-testutils-fonts"))
+        androidTestImplementation(project(":test:screenshot:screenshot"))
+        androidTestImplementation(project(":internal-testutils-runtime"))
+        androidTestImplementation(libs.testUiautomator)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testMonitor)
+        androidTestImplementation "androidx.activity:activity-compose:1.3.1"
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.kotlinTest)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.mockitoKotlin)
+
+        lintChecks(project(":compose:foundation:foundation-lint"))
+        lintPublish(project(":compose:foundation:foundation-lint"))
+
+        samples(project(":compose:foundation:foundation:foundation-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 api(project(':compose:animation:animation'))
                 api(project(':compose:runtime:runtime'))
                 api(project(':compose:ui:ui'))
                 implementation(project(":compose:ui:ui-text"))
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:ui:ui-util"))
                 implementation(project(':compose:foundation:foundation-layout'))
             }
-        }
-        androidMain.dependencies {
-            api("androidx.annotation:annotation:1.1.0")
-            implementation(project(':emoji2:emoji2'))
-            implementation("androidx.core:core:1.9.0")
-        }
+            androidMain.dependencies {
+                api("androidx.annotation:annotation:1.1.0")
+                implementation(project(':emoji2:emoji2'))
+                implementation("androidx.core:core:1.9.0")
+            }
 
-        commonTest {
-            dependencies {
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
+            }
+
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.mockitoCore4)
+                implementation(libs.truth)
+                implementation(libs.kotlinReflect)
+                implementation(libs.mockitoKotlin4)
+            }
+
+            commonTest.dependencies {
                 implementation(libs.kotlinTest)
                 implementation(libs.kotlinCoroutinesTest)
             }
-        }
 
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                api("androidx.annotation:annotation:1.1.0")
-                implementation(project(':emoji2:emoji2'))
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-
-                    implementation(project(":compose:ui:ui-util"))
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:test-utils"))
                 implementation(project(":internal-testutils-fonts"))
                 implementation(project(":test:screenshot:screenshot"))
@@ -110,47 +153,20 @@
                 implementation(libs.mockitoCore)
                 implementation(libs.mockitoKotlin)
             }
-        }
 
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.mockitoCore4)
+            desktopTest.dependencies {
+                implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(libs.truth)
-                implementation(libs.kotlinReflect)
-                implementation(libs.mockitoKotlin4)
-                implementation(project(":constraintlayout:constraintlayout-compose"))
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                    implementation(libs.truth)
-                    implementation(libs.junit)
-                    implementation(libs.skikoCurrentOs)
-                    implementation(libs.mockitoCore)
-                    implementation(libs.mockitoKotlin)
-                }
+                implementation(libs.junit)
+                implementation(libs.skikoCurrentOs)
+                implementation(libs.mockitoCore)
+                implementation(libs.mockitoKotlin)
             }
         }
     }
-}
-
-dependencies {
-    lintChecks(project(":compose:foundation:foundation-lint"))
-    lintPublish(project(":compose:foundation:foundation-lint"))
+    dependencies {
+        samples(project(":compose:foundation:foundation:foundation-samples"))
+    }
 }
 
 // Screenshot tests related setup
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
index f38975d..5df02d0 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
@@ -16,6 +16,7 @@
 
 package androidx.compose.foundation.demos.text
 
+import androidx.compose.foundation.demos.text2.BasicSecureTextFieldDemos
 import androidx.compose.foundation.demos.text2.BasicTextField2Demos
 import androidx.compose.foundation.demos.text2.BasicTextField2FilterDemos
 import androidx.compose.foundation.demos.text2.ScrollableDemos
@@ -137,6 +138,9 @@
                 ComposableDemo("Filters") {
                     BasicTextField2FilterDemos()
                 },
+                ComposableDemo("Secure Field") {
+                    BasicSecureTextFieldDemos()
+                }
             )
         ),
         DemoCategory(
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt
new file mode 100644
index 0000000..c4030ea
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicSecureTextFieldDemos.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.demos.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.demos.text.TagLine
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text2.BasicSecureTextField
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Icon
+import androidx.compose.material.IconToggleButton
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Info
+import androidx.compose.material.icons.filled.Warning
+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.graphics.Color
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.dp
+import androidx.core.text.isDigitsOnly
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun BasicSecureTextFieldDemos() {
+    Column(
+        Modifier
+            .imePadding()
+            .verticalScroll(rememberScrollState())
+    ) {
+        TagLine(tag = "Visible")
+        BasicSecureTextFieldDemo(TextObfuscationMode.Visible)
+
+        TagLine(tag = "RevealLastTyped")
+        BasicSecureTextFieldDemo(TextObfuscationMode.RevealLastTyped)
+
+        TagLine(tag = "Hidden")
+        BasicSecureTextFieldDemo(TextObfuscationMode.Hidden)
+
+        TagLine(tag = "Number Password")
+        NumberPasswordDemo()
+
+        TagLine(tag = "Password Toggle Visibility")
+        PasswordToggleVisibilityDemo()
+    }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun BasicSecureTextFieldDemo(textObfuscationMode: TextObfuscationMode) {
+    val state = remember { TextFieldState() }
+    BasicSecureTextField(
+        state = state,
+        textObfuscationMode = textObfuscationMode,
+        modifier = demoTextFieldModifiers
+    )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun NumberPasswordDemo() {
+    val state = remember { TextFieldState() }
+    BasicSecureTextField(
+        state = state,
+        filter = { _, new ->
+            if (!new.isDigitsOnly()) {
+                new.revertAllChanges()
+            }
+        },
+        keyboardType = KeyboardType.NumberPassword,
+        imeAction = ImeAction.Default,
+        modifier = demoTextFieldModifiers
+    )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun PasswordToggleVisibilityDemo() {
+    val state = remember { TextFieldState() }
+    var visible by remember { mutableStateOf(false) }
+    Row(Modifier.fillMaxWidth()) {
+        BasicSecureTextField(
+            state = state,
+            textObfuscationMode = if (visible) {
+                TextObfuscationMode.Visible
+            } else {
+                TextObfuscationMode.RevealLastTyped
+            },
+            modifier = Modifier
+                .weight(1f)
+                .padding(6.dp)
+                .border(1.dp, Color.LightGray, RoundedCornerShape(6.dp))
+                .padding(6.dp)
+        )
+        IconToggleButton(checked = visible, onCheckedChange = { visible = it }) {
+            if (visible) {
+                Icon(Icons.Default.Warning, "")
+            } else {
+                Icon(Icons.Default.Info, "")
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt
index ff35b95..d02309a9 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2Demos.kt
@@ -23,6 +23,7 @@
 import androidx.compose.foundation.layout.imePadding
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.text2.BasicTextField2
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.LocalTextStyle
@@ -67,7 +68,7 @@
         state = state,
         modifier = demoTextFieldModifiers,
         textStyle = LocalTextStyle.current,
-        maxLines = 1
+        lineLimits = TextFieldLineLimits.SingleLine
     )
 }
 
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt
index 7fd9627..b0e09b9 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/BasicTextField2FilterDemos.kt
@@ -27,8 +27,11 @@
 import androidx.compose.foundation.samples.BasicTextField2ChangeIterationSample
 import androidx.compose.foundation.samples.BasicTextField2ChangeReverseIterationSample
 import androidx.compose.foundation.samples.BasicTextField2CustomFilterSample
+import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text2.BasicTextField2
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.allCaps
 import androidx.compose.foundation.text2.input.maxLengthInChars
@@ -36,6 +39,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.intl.Locale
 import androidx.core.text.isDigitsOnly
 
@@ -55,7 +59,7 @@
         TagLine(tag = "Digits Only BasicTextField2")
         DigitsOnlyBasicTextField2()
 
-        TagLine(tag = "Custom (wrap the text in parentheses)")
+        TagLine(tag = "Custom (type backwards with prompt)")
         Box(demoTextFieldModifiers, propagateMinConstraints = true) {
             BasicTextField2CustomFilterSample()
         }
@@ -75,9 +79,18 @@
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun DigitsOnlyBasicTextField2() {
-    FilterDemo(filter = { old, new ->
-        if (!new.isDigitsOnly()) {
-            new.resetTo(old)
+    FilterDemo(filter = object : TextEditFilter {
+        override val keyboardOptions = KeyboardOptions(
+            keyboardType = KeyboardType.Number
+        )
+
+        override fun filter(
+            originalValue: TextFieldCharSequence,
+            valueWithChanges: TextFieldBufferWithSelection
+        ) {
+            if (!valueWithChanges.isDigitsOnly()) {
+                valueWithChanges.revertAllChanges()
+            }
         }
     })
 }
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
index fbd89fb..6b7c425 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
@@ -49,7 +49,7 @@
         textStyle = LocalTextStyle.current,
         decorationBox = @Composable {
             TextFieldDefaults.OutlinedTextFieldDecorationBox(
-                value = state.value.text,
+                value = state.text.toString(),
                 visualTransformation = VisualTransformation.None,
                 innerTextField = it,
                 placeholder = null,
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt
index 339c3dc..3590e8e 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/KeyboardOptionsDemos.kt
@@ -36,7 +36,6 @@
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 
@@ -67,7 +66,7 @@
     imeAction: ImeAction = ImeAction.Default,
     text: String = ""
 ) {
-    val state = remember { TextFieldState(TextFieldValue(text)) }
+    val state = remember { TextFieldState(text) }
     BasicTextField2(
         modifier = demoTextFieldModifiers,
         state = state,
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
index 3d3db19..d639aea 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
@@ -21,18 +21,20 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.text2.BasicTextField2
 import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.material.Slider
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import kotlin.math.roundToInt
@@ -47,6 +49,16 @@
         }
 
         item {
+            TagLine(tag = "SingleLine Horizontal Scroll with newlines")
+            SingleLineHorizontalScrollableTextFieldWithNewlines()
+        }
+
+        item {
+            TagLine(tag = "SingleLine Vertical Scroll")
+            SingleLineVerticalScrollableTextField()
+        }
+
+        item {
             TagLine(tag = "MultiLine Vertical Scroll")
             MultiLineVerticalScrollableTextField()
         }
@@ -67,25 +79,64 @@
 @Composable
 fun SingleLineHorizontalScrollableTextField() {
     val state = remember {
-        TextFieldState("When content gets long, this field should scroll horizontally")
+        TextFieldState("When content gets long,this field should scroll horizontally")
     }
     BasicTextField2(
         state = state,
-        maxLines = 1,
+        lineLimits = SingleLine,
         textStyle = TextStyle(fontSize = 24.sp)
     )
 }
 
+// TODO this is not supported currently. Add tests for this when supported.
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineHorizontalScrollableTextFieldWithNewlines() {
+    val state = remember {
+        TextFieldState("This \ntext \ncontains \nnewlines \nbut \nis \nsingle-line.")
+    }
+    BasicTextField2(
+        state = state,
+        lineLimits = SingleLine,
+        textStyle = TextStyle(fontSize = 24.sp)
+    )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun SingleLineVerticalScrollableTextField() {
+    val state = remember {
+        TextFieldState(
+            buildString {
+                repeat(10) {
+                    appendLine("When content gets long, this field should scroll vertically")
+                }
+            })
+    }
+    BasicTextField2(
+        state = state,
+        textStyle = TextStyle(fontSize = 24.sp),
+        lineLimits = MultiLine(maxHeightInLines = 1)
+    )
+}
+
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun MultiLineVerticalScrollableTextField() {
     val state = remember {
-        TextFieldState("When content gets long, this field should scroll vertically")
+        TextFieldState(
+            buildString {
+                repeat(10) {
+                    appendLine("When content gets long, this field should scroll vertically")
+                }
+            }
+        )
     }
     BasicTextField2(
         state = state,
         textStyle = TextStyle(fontSize = 24.sp),
-        modifier = Modifier.height(200.dp)
+        modifier = Modifier.heightIn(max = 200.dp),
+        lineLimits = MultiLine()
     )
 }
 
@@ -110,7 +161,7 @@
             scrollState = scrollState,
             textStyle = TextStyle(fontSize = 24.sp),
             modifier = Modifier.height(200.dp),
-            maxLines = 1
+            lineLimits = SingleLine
         )
     }
 }
@@ -139,17 +190,14 @@
             scrollState = scrollState,
             textStyle = TextStyle(fontSize = 24.sp),
             modifier = Modifier.fillMaxWidth(),
-            maxLines = 1
+            lineLimits = SingleLine
         )
         BasicTextField2(
             state = state2,
             scrollState = scrollState,
             textStyle = TextStyle(fontSize = 24.sp),
             modifier = Modifier.fillMaxWidth(),
-            maxLines = 1
+            lineLimits = SingleLine
         )
     }
-}
-
-@OptIn(ExperimentalFoundationApi::class)
-private fun TextFieldState(text: String) = TextFieldState(TextFieldValue(text))
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt
index cf1bf47..507a250 100644
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/BasicTextField2Samples.kt
@@ -14,42 +14,152 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalFoundationApi::class)
+@file:OptIn(ExperimentalFoundationApi::class, ExperimentalFoundationApi::class)
+@file:Suppress("UNUSED_PARAMETER", "unused", "LocalVariableName", "RedundantSuspendModifier")
 
 package androidx.compose.foundation.samples
 
 import androidx.annotation.Sampled
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.text2.BasicTextField2
 import androidx.compose.foundation.text2.input.TextEditFilter
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.delete
 import androidx.compose.foundation.text2.input.forEachChange
 import androidx.compose.foundation.text2.input.forEachChangeReversed
+import androidx.compose.foundation.text2.input.forEachTextValue
+import androidx.compose.foundation.text2.input.insert
 import androidx.compose.foundation.text2.input.rememberTextFieldState
 import androidx.compose.foundation.text2.input.selectCharsIn
+import androidx.compose.foundation.text2.input.setTextAndPlaceCursorAtEnd
+import androidx.compose.foundation.text2.input.textAsFlow
 import androidx.compose.foundation.text2.input.then
+import androidx.compose.material.Icon
+import androidx.compose.material.IconButton
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Clear
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.substring
+import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.debounce
+
+@Sampled
+fun BasicTextField2StateCompleteSample() {
+    class SearchViewModel(
+        val searchFieldState: TextFieldState = TextFieldState()
+    ) {
+        private val queryValidationRegex = """\w+""".toRegex()
+
+        // Use derived state to avoid recomposing every time the text changes, and only recompose
+        // when the input becomes valid or invalid.
+        val isQueryValid by derivedStateOf {
+            // This lambda will be re-executed every time inputState.text changes.
+            searchFieldState.text.matches(queryValidationRegex)
+        }
+
+        var searchResults: List<String> by mutableStateOf(emptyList())
+            private set
+
+        /** Called while the view model is active, e.g. from a LaunchedEffect. */
+        suspend fun run() {
+            searchFieldState.forEachTextValue { queryText ->
+                // Start a new search every time the user types something valid. If the previous
+                // search is still being processed when the text is changed, it will be cancelled
+                // and this code will run again with the latest query text.
+                if (isQueryValid) {
+                    searchResults = performSearch(query = queryText)
+                }
+            }
+        }
+
+        fun clearQuery() {
+            searchFieldState.setTextAndPlaceCursorAtEnd("")
+        }
+
+        private suspend fun performSearch(query: CharSequence): List<String> {
+            TODO()
+        }
+    }
+
+    @Composable
+    fun SearchScreen(viewModel: SearchViewModel) {
+        Column {
+            Row {
+                BasicTextField2(viewModel.searchFieldState)
+                IconButton(onClick = { viewModel.clearQuery() }) {
+                    Icon(Icons.Default.Clear, contentDescription = "clear search query")
+                }
+            }
+            if (!viewModel.isQueryValid) {
+                Text("Invalid query", style = TextStyle(color = Color.Red))
+            }
+            LazyColumn {
+                items(viewModel.searchResults) {
+                    TODO()
+                }
+            }
+        }
+    }
+}
+
+@Sampled
+fun BasicTextField2TextDerivedStateSample() {
+    class ViewModel {
+        private val inputValidationRegex = """\w+""".toRegex()
+
+        val inputState = TextFieldState()
+
+        // Use derived state to avoid recomposing every time the text changes, and only recompose
+        // when the input becomes valid or invalid.
+        val isInputValid by derivedStateOf {
+            // This lambda will be re-executed every time inputState.text changes.
+            inputState.text.matches(inputValidationRegex)
+        }
+    }
+
+    @Composable
+    fun Screen(viewModel: ViewModel) {
+        Column {
+            BasicTextField2(viewModel.inputState)
+            if (!viewModel.isInputValid) {
+                Text("Input is invalid.", style = TextStyle(color = Color.Red))
+            }
+        }
+    }
+}
 
 @Sampled
 fun BasicTextField2StateEditSample() {
-    val state = TextFieldState(TextFieldValue("hello world"))
+    val state = TextFieldState("hello world!")
     state.edit {
         // Insert a comma after "hello".
-        replace(5, 5, ",") // = "hello, world"
+        insert(5, ",") // = "hello, world!"
 
-        // Delete "world".
-        replace(7, 12, "") // = "hello, "
+        // Delete the exclamation mark.
+        delete(12, 13) // = "hello, world"
 
         // Add a different name.
         append("Compose") // = "hello, Compose"
 
+        // Say goodbye.
+        replace(0, 5, "goodbye") // "goodbye, Compose"
+
         // Select the new name so the user can change it by just starting to type.
-        selectCharsIn(TextRange(7, 14)) // "hello, ̲C̲o̲m̲p̲o̲s̲e"
+        selectCharsIn(TextRange(9, 16)) // "goodbye, ̲C̲o̲m̲p̲o̲s̲e"
     }
 }
 
@@ -57,20 +167,39 @@
 @Composable
 fun BasicTextField2CustomFilterSample() {
     val state = remember { TextFieldState() }
-    BasicTextField2(state, filter = { old, new ->
-        // If the old text was wrapped in parentheses, keep the text wrapped and preserve the
-        // cursor position or selection.
-        if (old.text.startsWith('(') && old.text.endsWith(')')) {
-            val selection = new.selectionInChars
-            if (!new.endsWith(')')) {
-                new.append(')')
-                new.selectCharsIn(TextRange(selection.start, selection.end))
-            }
-            if (!new.startsWith('(')) {
-                new.replace(0, 0, "(")
-                new.selectCharsIn(TextRange(selection.start + 1, selection.end + 1))
+    BasicTextField2(state, filter = { _, new ->
+        // A filter that always places newly-input text at the start of the string, after a
+        // prompt character, like a shell.
+        val promptChar = '>'
+
+        fun CharSequence.countPrefix(char: Char): Int {
+            var i = 0
+            while (i < length && get(i) == char) i++
+            return i
+        }
+
+        // Step one: Figure out the insertion point.
+        val newPromptChars = new.countPrefix(promptChar)
+        val insertionPoint = if (newPromptChars == 0) 0 else 1
+
+        // Step two: Ensure text is placed at the insertion point.
+        if (new.changes.changeCount == 1) {
+            val insertedRange = new.changes.getRange(0)
+            val replacedRange = new.changes.getOriginalRange(0)
+            if (!replacedRange.collapsed && insertedRange.collapsed) {
+                // Text was deleted, delete forwards from insertion point.
+                new.delete(insertionPoint, insertionPoint + replacedRange.length)
             }
         }
+        // Else text was replaced or there were multiple changes - don't handle.
+
+        // Step three: Ensure the prompt character is there.
+        if (newPromptChars == 0) {
+            new.insert(0, ">")
+        }
+
+        // Step four: Ensure the cursor is ready for the next input.
+        new.placeCursorAfterCharAt(0)
     })
 }
 
@@ -93,8 +222,8 @@
     printECountFilter.then(removeFirstEFilter)
 }
 
-@Composable
 @Sampled
+@Composable
 fun BasicTextField2ChangeIterationSample() {
     // Print a log message every time the text is changed.
     BasicTextField2(state = rememberTextFieldState(), filter = { _, new ->
@@ -105,8 +234,8 @@
     })
 }
 
-@Composable
 @Sampled
+@Composable
 fun BasicTextField2ChangeReverseIterationSample() {
     // Make a text field behave in "insert mode" – inserted text overwrites the text ahead of it
     // instead of being inserted.
@@ -121,4 +250,78 @@
             }
         }
     })
+}
+
+@Sampled
+fun BasicTextField2ForEachTextValueSample() {
+    class SearchViewModel {
+        val searchFieldState = TextFieldState()
+        var searchResults: List<String> by mutableStateOf(emptyList())
+            private set
+
+        /** Called while the view model is active, e.g. from a LaunchedEffect. */
+        suspend fun run() {
+            searchFieldState.forEachTextValue { queryText ->
+                // Start a new search every time the user types something. If the previous search
+                // is still being processed when the text is changed, it will be cancelled and this
+                // code will run again with the latest query text.
+                searchResults = performSearch(query = queryText)
+            }
+        }
+
+        private suspend fun performSearch(query: CharSequence): List<String> {
+            TODO()
+        }
+    }
+
+    @Composable
+    fun SearchScreen(viewModel: SearchViewModel) {
+        Column {
+            BasicTextField2(viewModel.searchFieldState)
+            LazyColumn {
+                items(viewModel.searchResults) {
+                    TODO()
+                }
+            }
+        }
+    }
+}
+
+@OptIn(FlowPreview::class)
+@Suppress("RedundantSuspendModifier")
+@Sampled
+fun BasicTextField2TextValuesSample() {
+    class SearchViewModel {
+        val searchFieldState = TextFieldState()
+        var searchResults: List<String> by mutableStateOf(emptyList())
+            private set
+
+        /** Called while the view model is active, e.g. from a LaunchedEffect. */
+        suspend fun run() {
+            searchFieldState.textAsFlow()
+                // Let fast typers get multiple keystrokes in before kicking off a search.
+                .debounce(500)
+                // collectLatest cancels the previous search if it's still running when there's a
+                // new change.
+                .collectLatest { queryText ->
+                    searchResults = performSearch(query = queryText)
+                }
+        }
+
+        private suspend fun performSearch(query: CharSequence): List<String> {
+            TODO()
+        }
+    }
+
+    @Composable
+    fun SearchScreen(viewModel: SearchViewModel) {
+        Column {
+            BasicTextField2(viewModel.searchFieldState)
+            LazyColumn {
+                items(viewModel.searchResults) {
+                    TODO()
+                }
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
index 9b004e2..3fe4f04 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
@@ -109,9 +109,7 @@
             overscrollEffect = controller
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).assertExists()
 
@@ -142,9 +140,7 @@
             overscrollEffect = controller
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).performTouchInput {
             down(center)
@@ -241,9 +237,7 @@
             flingBehavior = flingBehavior
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).assertExists()
 
@@ -469,9 +463,7 @@
             overscrollEffect = controller
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).assertExists()
 
@@ -511,9 +503,7 @@
             orientation = Orientation.Vertical
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).assertExists()
 
@@ -713,9 +703,7 @@
             reverseDirection = reverseDirection
         )
 
-        rule.runOnIdle {
-            assertThat(controller.drawCallsCount).isEqualTo(1)
-        }
+        rule.waitUntil { controller.drawCallsCount == 1 }
 
         rule.onNodeWithTag(boxTag).assertExists()
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/BasicTextGraphicsLayerTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/BasicTextGraphicsLayerTest.kt
new file mode 100644
index 0000000..9c1ba16
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/BasicTextGraphicsLayerTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text
+
+import androidx.compose.ui.layout.GraphicLayerInfo
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.text.AnnotatedString
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class BasicTextGraphicsLayerTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun modifiersExposeGraphicsLayer() {
+        rule.setContent {
+            BasicText("Ok")
+        }
+        // ui-inspector 3d view requires this to be emitted
+        val owners = rule.onNodeWithText("Ok").fetchGraphicsLayerOwnerViewId()
+        assertThat(owners).hasSize(1)
+    }
+
+    @Test
+    fun modifiersExposeGraphicsLayer_annotatedString() {
+        rule.setContent {
+            BasicText(AnnotatedString("Ok"))
+        }
+        // ui-inspector 3d view requires this to be emitted
+        val owners = rule.onNodeWithText("Ok").fetchGraphicsLayerOwnerViewId()
+        assertThat(owners).hasSize(1)
+    }
+}
+
+private fun SemanticsNodeInteraction.fetchGraphicsLayerOwnerViewId(): List<Long> =
+    fetchSemanticsNode()
+        .layoutInfo
+        .getModifierInfo()
+        .map { it.extra }
+        .filterIsInstance<GraphicLayerInfo>()
+        .map { it.ownerViewId }
+        .distinct()
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt
new file mode 100644
index 0000000..fe5e726
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicSecureTextFieldTest.kt
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTextInput
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.test.performTextReplacement
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class BasicSecureTextFieldTest {
+
+    @get:Rule
+    val rule = createComposeRule().apply {
+        mainClock.autoAdvance = false
+    }
+
+    private val Tag = "BasicSecureTextField"
+
+    @Test
+    fun passwordSemanticsAreSet() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        rule.onNodeWithTag(Tag).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Password))
+    }
+
+    @Test
+    fun lastTypedCharacterIsRevealedTemporarily() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("a")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+            rule.mainClock.advanceTimeBy(1500)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022")
+        }
+    }
+
+    @Test
+    fun lastTypedCharacterIsRevealed_hidesAfterAnotherCharacterIsTyped() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("a")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+            performTextInput("b")
+            rule.mainClock.advanceTimeBy(50)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022b")
+        }
+    }
+
+    @OptIn(ExperimentalTestApi::class)
+    @Test
+    fun lastTypedCharacterIsRevealed_whenInsertedInMiddle() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022")
+            performTextInputSelection(TextRange(1))
+            performTextInput("d")
+            rule.mainClock.advanceTimeBy(50)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022d\u2022\u2022")
+        }
+    }
+
+    @Test
+    fun lastTypedCharacterIsRevealed_hidesAfterFocusIsLost() {
+        val focusRequester = FocusRequester()
+        rule.setContent {
+            Column {
+                BasicSecureTextField(
+                    state = rememberTextFieldState(),
+                    modifier = Modifier.testTag(Tag)
+                )
+                Box(modifier = Modifier
+                    .size(1.dp)
+                    .focusRequester(focusRequester)
+                    .focusable()
+                )
+            }
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("a")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("a")
+            focusRequester.requestFocus()
+            rule.mainClock.advanceTimeBy(50)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text).isEqualTo("\u2022")
+        }
+    }
+
+    @Test
+    fun lastTypedCharacterIsRevealed_hidesAfterAnotherCharacterRemoved() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeBy(200)
+            performTextInput("d")
+            rule.mainClock.advanceTimeBy(50)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022d")
+            performTextReplacement("bcd")
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022")
+        }
+    }
+
+    @Test
+    fun obfuscationMethodVisible_doesNotHideAnything() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                textObfuscationMode = TextObfuscationMode.Visible,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("abc")
+            rule.mainClock.advanceTimeBy(1500)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("abc")
+        }
+    }
+
+    @Test
+    fun obfuscationMethodVisible_revealsEverythingWhenSwitchedTo() {
+        var obfuscationMode by mutableStateOf(TextObfuscationMode.Hidden)
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                textObfuscationMode = obfuscationMode,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeBy(200)
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022")
+            obfuscationMode = TextObfuscationMode.Visible
+            rule.mainClock.advanceTimeByFrame()
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("abc")
+        }
+    }
+
+    @Test
+    fun obfuscationMethodHidden_hidesEverything() {
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                textObfuscationMode = TextObfuscationMode.Hidden,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeByFrame()
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022")
+            performTextInput("d")
+            rule.mainClock.advanceTimeByFrame()
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022\u2022")
+        }
+    }
+
+    @Test
+    fun obfuscationMethodHidden_hidesEverythingWhenSwitchedTo() {
+        var obfuscationMode by mutableStateOf(TextObfuscationMode.Visible)
+        rule.setContent {
+            BasicSecureTextField(
+                state = rememberTextFieldState(),
+                textObfuscationMode = obfuscationMode,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            performTextInput("abc")
+            rule.mainClock.advanceTimeByFrame()
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("abc")
+            obfuscationMode = TextObfuscationMode.Hidden
+            rule.mainClock.advanceTimeByFrame()
+            assertThat(fetchTextLayoutResult().layoutInput.text.text)
+                .isEqualTo("\u2022\u2022\u2022")
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
index fd35f07..230447f 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2ImmIntegrationTest.kt
@@ -41,7 +41,6 @@
 import androidx.compose.ui.test.performSemanticsAction
 import androidx.compose.ui.test.pressKey
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
@@ -266,7 +265,7 @@
 
     @Test
     fun immUpdated_whenEditChangesSelection() {
-        val state = TextFieldState(TextFieldValue("hello", selection = TextRange(0)))
+        val state = TextFieldState("hello", initialSelectionInChars = TextRange(0))
         rule.setContent {
             BasicTextField2(state, Modifier.testTag(Tag))
         }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt
index 85969b8..2761b7e 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2SemanticsTest.kt
@@ -5,6 +5,7 @@
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -35,7 +36,6 @@
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
@@ -81,6 +81,7 @@
                 )
             )
             .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.SetText))
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Password))
             // TODO(halilibo): enable after selection work is completed.
             // .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.SetSelection))
             .assert(SemanticsMatcher.keyIsDefined(SemanticsActions.GetTextLayoutResult))
@@ -146,7 +147,7 @@
 
     @Test
     fun contentSemanticsAreSet_inTheFirstComposition() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -159,7 +160,7 @@
 
     @Test
     fun contentSemanticsAreSet_afterRecomposition() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -169,14 +170,14 @@
 
         rule.onNodeWithTag(Tag).assertTextEquals("hello")
 
-        state.editProcessor.reset(TextFieldValue("hello2"))
+        state.editProcessor.reset(TextFieldCharSequence("hello2"))
 
         rule.onNodeWithTag(Tag).assertTextEquals("hello2")
     }
 
     @Test
     fun selectionSemanticsAreSet_inTheFirstComposition() {
-        val state = TextFieldState(TextFieldValue("hello", selection = TextRange(2)))
+        val state = TextFieldState("hello", initialSelectionInChars = TextRange(2))
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -192,7 +193,7 @@
 
     @Test
     fun selectionSemanticsAreSet_afterRecomposition() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -205,7 +206,7 @@
             assertSelection(TextRange.Zero)
         }
 
-        state.editProcessor.reset(TextFieldValue("hello", selection = TextRange(2)))
+        state.editProcessor.reset(TextFieldCharSequence("hello", selection = TextRange(2)))
 
         with(rule.onNodeWithTag(Tag)) {
             assertTextEquals("hello")
@@ -216,7 +217,7 @@
     @OptIn(ExperimentalTestApi::class)
     @Test
     fun inputSelection_changesSelectionState() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -227,13 +228,13 @@
         rule.onNodeWithTag(Tag).performTextInputSelection(TextRange(2))
 
         rule.runOnIdle {
-            assertThat(state.value.selection).isEqualTo(TextRange(2))
+            assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
         }
     }
 
     @Test
     fun textLayoutResultSemanticsAreSet_inTheFirstComposition() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -266,8 +267,8 @@
 
     @Test
     fun semanticsAreSet_afterStateObjectChanges() {
-        val state1 = TextFieldState(TextFieldValue("hello"))
-        val state2 = TextFieldState(TextFieldValue("world", TextRange(2)))
+        val state1 = TextFieldState("hello")
+        val state2 = TextFieldState("world", TextRange(2))
         var chosenState by mutableStateOf(true)
         rule.setContent {
             BasicTextField2(
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt
index 837dc2c..6a7ba4b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/BasicTextField2Test.kt
@@ -20,14 +20,21 @@
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputConnection
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.text.KeyboardHelper
 import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList
-import androidx.compose.foundation.text2.input.MutableTextFieldValueWithSelection
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.internal.AndroidTextInputAdapter
+import androidx.compose.foundation.text2.input.rememberTextFieldState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -53,7 +60,10 @@
 import androidx.compose.ui.test.performTextInput
 import androidx.compose.ui.test.performTextInputSelection
 import androidx.compose.ui.test.performTextReplacement
+import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextRange
@@ -61,10 +71,11 @@
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Ignore
@@ -106,7 +117,7 @@
 
     @Test
     fun textField_contentChange_updatesState() {
-        val state = TextFieldState(TextFieldValue("Hello ", TextRange(Int.MAX_VALUE)))
+        val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -119,7 +130,7 @@
         rule.onNodeWithTag(Tag).performTextInput("World!")
 
         rule.runOnIdle {
-            assertThat(state.value.text).isEqualTo("Hello World!")
+            assertThat(state.text.toString()).isEqualTo("Hello World!")
         }
 
         rule.onNodeWithTag(Tag).assertTextEquals("Hello World!")
@@ -160,7 +171,7 @@
 
     @Test
     fun textField_textStyleFontSizeChange_relayouts() {
-        val state = TextFieldState(TextFieldValue("Hello ", TextRange(Int.MAX_VALUE)))
+        val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
         var style by mutableStateOf(TextStyle(fontSize = 20.sp))
         val textLayoutResults = mutableListOf<TextLayoutResult>()
         rule.setContent {
@@ -185,7 +196,7 @@
 
     @Test
     fun textField_textStyleColorChange_doesNotRelayout() {
-        val state = TextFieldState(TextFieldValue("Hello"))
+        val state = TextFieldState("Hello")
         var style by mutableStateOf(TextStyle(color = Color.Red))
         val textLayoutResults = mutableListOf<TextLayoutResult>()
         rule.setContent {
@@ -210,7 +221,7 @@
 
     @Test
     fun textField_contentChange_relayouts() {
-        val state = TextFieldState(TextFieldValue("Hello ", TextRange(Int.MAX_VALUE)))
+        val state = TextFieldState("Hello ", TextRange(Int.MAX_VALUE))
         val textLayoutResults = mutableListOf<TextLayoutResult>()
         rule.setContent {
             BasicTextField2(
@@ -284,8 +295,8 @@
 
     @Test
     fun textField_whenStateObjectChanges_newTextIsRendered() {
-        val state1 = TextFieldState(TextFieldValue("Hello"))
-        val state2 = TextFieldState(TextFieldValue("World"))
+        val state1 = TextFieldState("Hello")
+        val state2 = TextFieldState("World")
         var toggleState by mutableStateOf(true)
         val state by derivedStateOf { if (toggleState) state1 else state2 }
         rule.setContent {
@@ -305,8 +316,8 @@
 
     @Test
     fun textField_whenStateObjectChanges_restartsInput() {
-        val state1 = TextFieldState(TextFieldValue("Hello"))
-        val state2 = TextFieldState(TextFieldValue("World"))
+        val state1 = TextFieldState("Hello")
+        val state2 = TextFieldState("World")
         var toggleState by mutableStateOf(true)
         val state by derivedStateOf { if (toggleState) state1 else state2 }
         rule.setContent {
@@ -328,8 +339,8 @@
             performTextReplacement("Compose2")
             assertTextEquals("Compose2")
         }
-        assertThat(state1.value.text).isEqualTo("Compose")
-        assertThat(state2.value.text).isEqualTo("Compose2")
+        assertThat(state1.text.toString()).isEqualTo("Compose")
+        assertThat(state2.text.toString()).isEqualTo("Compose2")
     }
 
     @Test
@@ -428,6 +439,7 @@
         rule.onNodeWithTag(Tag).assertTextEquals("")
     }
 
+    @Ignore("b/276932521")
     @Test
     fun textField_appliesFilter_toInputConnection_afterChanging() {
         var inputConnection: InputConnection? = null
@@ -604,7 +616,7 @@
         AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
             inputConnection = ic
         }
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         lateinit var changes: ChangeList
         rule.setContent {
             BasicTextField2(
@@ -640,7 +652,7 @@
         AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { _, ic ->
             inputConnection = ic
         }
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         lateinit var changes: ChangeList
         rule.setContent {
             BasicTextField2(
@@ -697,7 +709,7 @@
 
     @Test
     fun textField_changesAreTracked_whenKeyEventDeletes() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         lateinit var changes: ChangeList
         rule.setContent {
             BasicTextField2(
@@ -746,6 +758,190 @@
         }
     }
 
+    @Test
+    fun textField_filterKeyboardOptions_sentToIme() {
+        lateinit var editorInfo: EditorInfo
+        AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+            editorInfo = ei
+        }
+        val filter = KeyboardOptionsFilter(
+            KeyboardOptions(
+                keyboardType = KeyboardType.Email,
+                imeAction = ImeAction.Previous
+            )
+        )
+        rule.setContent {
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag),
+                filter = filter,
+            )
+        }
+        requestFocus(Tag)
+
+        rule.runOnIdle {
+            assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+            assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+                .isNotEqualTo(0)
+        }
+    }
+
+    @Test
+    fun textField_filterKeyboardOptions_mergedWithParams() {
+        lateinit var editorInfo: EditorInfo
+        AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+            editorInfo = ei
+        }
+        val filter = KeyboardOptionsFilter(KeyboardOptions(imeAction = ImeAction.Previous))
+        rule.setContent {
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag),
+                filter = filter,
+                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
+            )
+        }
+        requestFocus(Tag)
+
+        rule.runOnIdle {
+            assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+            assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+                .isNotEqualTo(0)
+        }
+    }
+
+    @Test
+    fun textField_filterKeyboardOptions_overriddenByParams() {
+        lateinit var editorInfo: EditorInfo
+        AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+            editorInfo = ei
+        }
+        val filter = KeyboardOptionsFilter(KeyboardOptions(imeAction = ImeAction.Previous))
+        rule.setContent {
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag),
+                filter = filter,
+                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
+            )
+        }
+        requestFocus(Tag)
+
+        rule.runOnIdle {
+            assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_SEARCH).isNotEqualTo(0)
+        }
+    }
+
+    @Test
+    fun textField_filterKeyboardOptions_applyWhenFilterChanged() {
+        lateinit var editorInfo: EditorInfo
+        AndroidTextInputAdapter.setInputConnectionCreatedListenerForTests { ei, _ ->
+            editorInfo = ei
+        }
+        var filter by mutableStateOf(
+            KeyboardOptionsFilter(
+                KeyboardOptions(
+                    keyboardType = KeyboardType.Email,
+                    imeAction = ImeAction.Previous
+                )
+            )
+        )
+        rule.setContent {
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag),
+                filter = filter,
+            )
+        }
+        requestFocus(Tag)
+
+        rule.runOnIdle {
+            assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_PREVIOUS).isNotEqualTo(0)
+            assertThat(editorInfo.inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
+                .isNotEqualTo(0)
+        }
+
+        filter = KeyboardOptionsFilter(
+            KeyboardOptions(
+                keyboardType = KeyboardType.Decimal,
+                imeAction = ImeAction.Search
+            )
+        )
+
+        rule.runOnIdle {
+            assertThat(editorInfo.imeOptions and EditorInfo.IME_ACTION_SEARCH).isNotEqualTo(0)
+            assertThat(editorInfo.inputType and InputType.TYPE_NUMBER_FLAG_DECIMAL)
+                .isNotEqualTo(0)
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = 23)
+    @Test
+    fun textField_showsKeyboardAgainWhenTapped_ifFocused() {
+        val keyboardHelper = KeyboardHelper(rule)
+        rule.setContent {
+            keyboardHelper.initialize()
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        // make sure keyboard is hidden initially
+        keyboardHelper.hideKeyboardIfShown()
+
+        // click the first time to gain focus.
+        rule.onNodeWithTag(Tag).performClick()
+        keyboardHelper.waitForKeyboardVisibility(true)
+        assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+
+        // hide it again.
+        keyboardHelper.hideKeyboardIfShown()
+        rule.onNodeWithTag(Tag).assertIsFocused()
+        rule.onNodeWithTag(Tag).performClick()
+
+        // expect keyboard to show up again.
+        keyboardHelper.waitForKeyboardVisibility(true)
+        assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
+    }
+
+    @Test
+    fun swipingThroughTextField_doesNotGainFocus() {
+        rule.setContent {
+            BasicTextField2(
+                state = rememberTextFieldState(),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        rule.onNodeWithTag(Tag).performTouchInput {
+            // swipe through
+            swipeRight(endX = right + 200, durationMillis = 1000)
+        }
+        rule.onNodeWithTag(Tag).assertIsNotFocused()
+    }
+
+    @Test
+    fun swipingTextFieldInScrollableContainer_doesNotGainFocus() {
+        val scrollState = ScrollState(0)
+        rule.setContent {
+            Column(Modifier.size(100.dp).verticalScroll(scrollState)) {
+                BasicTextField2(
+                    state = rememberTextFieldState(),
+                    modifier = Modifier.testTag(Tag)
+                )
+                Box(Modifier.size(200.dp))
+            }
+        }
+
+        rule.onNodeWithTag(Tag).performTouchInput {
+            // swipe through
+            swipeUp(durationMillis = 1000)
+        }
+        rule.onNodeWithTag(Tag).assertIsNotFocused()
+        assertThat(scrollState.value).isNotEqualTo(0)
+    }
+
     private fun requestFocus(tag: String) =
         rule.onNodeWithTag(tag).performSemanticsAction(SemanticsActions.RequestFocus)
 
@@ -758,10 +954,20 @@
 
     private object RejectAllTextFilter : TextEditFilter {
         override fun filter(
-            oldState: TextFieldValue,
-            newState: MutableTextFieldValueWithSelection
+            originalValue: TextFieldCharSequence,
+            valueWithChanges: TextFieldBufferWithSelection
         ) {
-            newState.resetTo(oldState)
+            valueWithChanges.revertAllChanges()
+        }
+    }
+
+    private class KeyboardOptionsFilter(override val keyboardOptions: KeyboardOptions) :
+        TextEditFilter {
+        override fun filter(
+            originalValue: TextFieldCharSequence,
+            valueWithChanges: TextFieldBufferWithSelection
+        ) {
+            // Noop
         }
     }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt
index db1e0b4..673dd9e 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/DecorationBoxTest.kt
@@ -45,7 +45,6 @@
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.pressKey
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -95,7 +94,7 @@
 
     @Test
     fun semanticsAreAppliedOnDecoratedComposable() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -122,7 +121,7 @@
 
     @Test
     fun clickGestureIsAppliedOnDecoratedComposable() {
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -174,7 +173,7 @@
         }
 
         rule.runOnIdle {
-            assertThat(state.value.text).isEqualTo("hello")
+            assertThat(state.text.toString()).isEqualTo("hello")
         }
     }
 
@@ -209,7 +208,7 @@
         }
 
         rule.runOnIdle {
-            assertThat(state.value.text).isEqualTo("hello")
+            assertThat(state.text.toString()).isEqualTo("hello")
         }
     }
 
@@ -217,7 +216,7 @@
     @Test
     fun longClickGestureIsAppliedOnDecoratedComposable() {
         // create a decorated BasicTextField2
-        val state = TextFieldState(TextFieldValue("hello"))
+        val state = TextFieldState("hello")
         rule.setContent {
             BasicTextField2(
                 state = state,
@@ -243,7 +242,7 @@
 
         // assertThat selection happened
         rule.runOnIdle {
-            assertThat(state.value.selection).isEqualTo(TextRange(0, 5))
+            assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
         }
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt
index 758e083..4a9dab6 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/HeightInLinesModifierTest.kt
@@ -26,6 +26,7 @@
 import androidx.compose.foundation.text.TEST_FONT
 import androidx.compose.foundation.text.heightInLines
 import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.remember
@@ -47,7 +48,6 @@
 import androidx.compose.ui.text.font.FontVariation
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.font.createFontFamilyResolver
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
@@ -64,6 +64,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalFoundationApi::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class HeightInLinesModifierTest {
@@ -97,7 +98,7 @@
                     subjectLayout = it
                 },
                 text = "abc",
-                minLines = 2
+                lineLimits = MultiLine(minHeightInLines = 2)
             )
             HeightObservingText(
                 onGlobalHeightPositioned = {
@@ -106,7 +107,7 @@
                 },
                 onTextLayoutResult = {},
                 text = "1\n2",
-                minLines = 2
+                lineLimits = MultiLine(minHeightInLines = 2)
             )
         }
         assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
@@ -123,7 +124,7 @@
     fun maxLines_shortInputText() {
         val (textLayoutResult, height) = setTextFieldWithMaxLines(
             text = "abc",
-            maxLines = 5
+            lines = MultiLine(maxHeightInLines = 5)
         )
 
         rule.runOnIdle {
@@ -136,7 +137,7 @@
     @Test
     fun maxLines_notApplied_infiniteMaxLines() {
         val (textLayoutResult, height) =
-            setTextFieldWithMaxLines(longText, Int.MAX_VALUE)
+            setTextFieldWithMaxLines(longText, MultiLine(minHeightInLines = Int.MAX_VALUE))
 
         rule.runOnIdle {
             assertThat(textLayoutResult).isNotNull()
@@ -179,7 +180,7 @@
     fun minLines_longInputText() {
         val (textLayoutResult, height) = setTextFieldWithMaxLines(
             text = longText,
-            minLines = 2
+            MultiLine(minHeightInLines = 2)
         )
 
         rule.runOnIdle {
@@ -208,7 +209,7 @@
                     subjectLayout = it
                 },
                 text = longText,
-                maxLines = 2
+                lineLimits = MultiLine(maxHeightInLines = 2)
             )
             HeightObservingText(
                 onGlobalHeightPositioned = {
@@ -217,7 +218,7 @@
                 },
                 onTextLayoutResult = {},
                 text = "1\n2",
-                maxLines = 2
+                lineLimits = MultiLine(maxHeightInLines = 2)
             )
         }
         assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
@@ -267,7 +268,7 @@
                     },
                     onTextLayoutResult = {},
                     text = longText,
-                    maxLines = 10,
+                    lineLimits = MultiLine(maxHeightInLines = 10),
                     textStyle = TextStyle.Default.copy(
                         fontFamily = fontFamily,
                         fontSize = 80.sp
@@ -306,8 +307,7 @@
 
     private fun setTextFieldWithMaxLines(
         text: String,
-        minLines: Int = 1,
-        maxLines: Int = Int.MAX_VALUE
+        lines: MultiLine
     ): Pair<TextLayoutResult?, Int?> {
         var textLayoutResult: TextLayoutResult? = null
         var height: Int? = null
@@ -323,8 +323,7 @@
                     textLayoutResult = it
                 },
                 text = text,
-                minLines = minLines,
-                maxLines = maxLines
+                lineLimits = lines
             )
         }
         assertThat(positionedLatch.await(1, TimeUnit.SECONDS)).isTrue()
@@ -337,8 +336,7 @@
         onGlobalHeightPositioned: (Int) -> Unit,
         onTextLayoutResult: Density.(TextLayoutResult) -> Unit,
         text: String,
-        minLines: Int = 1,
-        maxLines: Int = Int.MAX_VALUE,
+        lineLimits: MultiLine,
         textStyle: TextStyle = TextStyle.Default
     ) {
         Box(
@@ -347,10 +345,9 @@
             }
         ) {
             BasicTextField2(
-                state = remember { TextFieldState(TextFieldValue(text)) },
+                state = remember { TextFieldState(text) },
                 textStyle = textStyle,
-                minLines = minLines,
-                maxLines = maxLines,
+                lineLimits = lineLimits,
                 modifier = Modifier.requiredWidth(100.dp),
                 onTextLayout = onTextLayoutResult
             )
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt
new file mode 100644
index 0000000..45f4155
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCodepointTransformationTest.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.selection.fetchTextLayoutResult
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.mask
+import androidx.compose.foundation.text2.input.setTextAndPlaceCursorAtEnd
+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.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTextInput
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class TextFieldCodepointTransformationTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    private val Tag = "BasicTextField2"
+
+    @Test
+    fun textField_rendersTheResultOf_codepointTransformation() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = { _, codepoint -> codepoint + 1 },
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Ifmmp") // one character after in lexical order
+    }
+
+    @Test
+    fun textField_rendersTheResultOf_codepointTransformation_codepointIndex() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = { index, codepoint ->
+                    if (index % 2 == 0) codepoint + 1 else codepoint - 1
+                },
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Idmkp") // one character after and before in lexical order
+    }
+
+    @Test
+    fun textField_toggleCodepointTransformation_affectsNextFrame() {
+        rule.mainClock.autoAdvance = false
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        var codepointTransformation by mutableStateOf(CodepointTransformation.None)
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = codepointTransformation,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Hello") // no change
+        codepointTransformation = CodepointTransformation.mask('c')
+
+        rule.mainClock.advanceTimeByFrame()
+        assertLayoutText("ccccc") // all characters turn to c
+    }
+
+    @Test
+    fun textField_statefulCodepointTransformation_reactsToStateChange() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        var mask by mutableStateOf('-')
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = CodepointTransformation.mask(mask),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("-----")
+        mask = '@'
+
+        rule.waitForIdle()
+        assertLayoutText("@@@@@")
+    }
+
+    @Test
+    fun textField_removingCodepointTransformation_rendersTextNormally() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        var codepointTransformation by mutableStateOf<CodepointTransformation?>(
+            CodepointTransformation.mask('*')
+        )
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = codepointTransformation,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("*****")
+        codepointTransformation = null
+
+        rule.waitForIdle()
+        assertLayoutText("Hello")
+    }
+
+    @Test
+    fun textField_codepointTransformation_continuesToRenderUpdatedText() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                codepointTransformation = CodepointTransformation.mask('*'),
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("*****")
+        rule.waitForIdle()
+        rule.onNodeWithTag(Tag).performTextInput(", World!")
+        assertLayoutText("*".repeat("Hello, World!".length))
+    }
+
+    @Test
+    fun textField_singleLine_removesLineFeedViaCodepointTransformation() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello\nWorld")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                lineLimits = TextFieldLineLimits.SingleLine,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Hello World")
+        rule.onNodeWithTag(Tag).performTextInput("\n")
+        assertLayoutText("Hello World ")
+    }
+
+    @Test
+    fun textField_singleLine_removesCarriageReturnViaCodepointTransformation() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello\rWorld")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                lineLimits = TextFieldLineLimits.SingleLine,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Hello\uFEFFWorld")
+    }
+
+    @Test
+    fun textField_singleLine_doesNotOverrideGivenCodepointTransformation() {
+        val state = TextFieldState()
+        state.setTextAndPlaceCursorAtEnd("Hello\nWorld")
+        rule.setContent {
+            BasicTextField2(
+                state = state,
+                lineLimits = TextFieldLineLimits.SingleLine,
+                codepointTransformation = CodepointTransformation.None,
+                modifier = Modifier.testTag(Tag)
+            )
+        }
+
+        assertLayoutText("Hello\nWorld")
+    }
+
+    // TODO: add more tests when selection is added
+
+    private fun assertLayoutText(text: String) {
+        assertThat(rule.onNodeWithTag(Tag).fetchTextLayoutResult().layoutInput.text.text)
+            .isEqualTo(text)
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
index 6cea579..b615766 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
@@ -26,6 +26,7 @@
 import androidx.compose.foundation.text.TEST_FONT_FAMILY
 import androidx.compose.foundation.text.selection.LocalTextSelectionColors
 import androidx.compose.foundation.text.selection.TextSelectionColors
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
@@ -61,7 +62,6 @@
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntSize
@@ -73,7 +73,6 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.math.ceil
 import kotlin.math.floor
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 
@@ -109,7 +108,7 @@
     private var textLayoutResult: TextLayoutResult? = null
     private val cursorRect: Rect
         // assume selection is collapsed
-        get() = textLayoutResult?.getCursorRect(state.value.selection.start) ?: Rect.Zero
+        get() = textLayoutResult?.getCursorRect(state.text.selectionInChars.start) ?: Rect.Zero
 
     private val backgroundModifier = Modifier.background(contentColor)
     private val focusModifier = Modifier.onFocusChanged { if (it.isFocused) isFocused = true }
@@ -281,7 +280,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun cursorUnsetColor_noCursor() {
-        state = TextFieldState(TextFieldValue("hello", selection = TextRange(2)))
+        state = TextFieldState("hello", initialSelectionInChars = TextRange(2))
         rule.setContent {
             // The padding helps if the test is run accidentally in landscape. Landscape makes
             // the cursor to be next to the navigation bar which affects the red color to be a bit
@@ -325,7 +324,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun cursorNotBlinking_whileTyping() {
-        state = TextFieldState(TextFieldValue("test", selection = TextRange(4)))
+        state = TextFieldState("test", initialSelectionInChars = TextRange(4))
         rule.setContent {
             // The padding helps if the test is run accidentally in landscape. Landscape makes
             // the cursor to be next to the navigation bar which affects the red color to be a bit
@@ -363,7 +362,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun selectionChanges_cursorNotBlinking() {
-        state = TextFieldState(TextFieldValue("test", selection = TextRange(2)))
+        state = TextFieldState("test", initialSelectionInChars = TextRange(2))
         rule.setContent {
             // The padding helps if the test is run accidentally in landscape. Landscape makes
             // the cursor to be next to the navigation bar which affects the red color to be a bit
@@ -436,7 +435,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun selectionNotCollapsed_cursorNotDrawn() {
-        state = TextFieldState(TextFieldValue("test", selection = TextRange(2, 3)))
+        state = TextFieldState("test", initialSelectionInChars = TextRange(2, 3))
         rule.setContent {
             // The padding helps if the test is run accidentally in landscape. Landscape makes
             // the cursor to be next to the navigation bar which affects the red color to be a bit
@@ -474,7 +473,7 @@
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun focusLost_cursorHidesImmediately() {
-        state = TextFieldState(TextFieldValue("test"))
+        state = TextFieldState("test")
         rule.setContent {
             // The padding helps if the test is run accidentally in landscape. Landscape makes
             // the cursor to be next to the navigation bar which affects the red color to be a bit
@@ -488,7 +487,9 @@
                     cursorBrush = SolidColor(cursorColor),
                     onTextLayout = onTextLayout
                 )
-                Box(modifier = Modifier.focusable(true).testTag("box"))
+                Box(modifier = Modifier
+                    .focusable(true)
+                    .testTag("box"))
             }
         }
 
@@ -564,10 +565,9 @@
         }
     }
 
-    @Ignore // (b/276789499) Ignore for now.
     @Test
     fun textFieldCursor_alwaysReadLatestState_duringDraw() {
-        state = TextFieldState(TextFieldValue("hello world", TextRange(5)))
+        state = TextFieldState("hello world", TextRange(5))
         rule.setContent {
             Box(Modifier.padding(boxPadding)) {
                 BasicTextField2(
@@ -575,10 +575,11 @@
                     textStyle = textStyle,
                     modifier = textFieldModifier.layout { measurable, constraints ->
                         // change the state during layout so draw can read the new state
-                        val currValue = state.value
-                        if (currValue.text.isNotEmpty()) {
-                            val newText = currValue.text.dropLast(1)
-                            val newValue = TextFieldValue(newText, TextRange(newText.length))
+                        val currValue = state.text
+                        if (currValue.isNotEmpty()) {
+                            val newText = currValue.dropLast(1)
+                            val newValue =
+                                TextFieldCharSequence(newText.toString(), TextRange(newText.length))
                             state.editProcessor.reset(newValue)
                         }
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
index 2bf620d..8c399e13 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
@@ -16,38 +16,38 @@
 
 package androidx.compose.foundation.text2
 
-import android.view.KeyEvent
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.text.TEST_FONT_FAMILY
 import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.nativeKeyCode
 import androidx.compose.ui.platform.LocalClipboardManager
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalTextInputService
-import androidx.compose.ui.test.SemanticsNodeInteraction
-import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.KeyInjectionScope
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.performKeyPress
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.test.withKeyDown
+import androidx.compose.ui.test.withKeysDown
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.text.input.TextInputService
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
-import com.google.common.truth.Truth
-import org.mockito.kotlin.mock
+import com.google.common.truth.Truth.assertThat
 import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
@@ -55,18 +55,23 @@
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
-@OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
+@OptIn(
+    ExperimentalFoundationApi::class,
+    ExperimentalTestApi::class
+)
 class TextFieldKeyEventTest {
     @get:Rule
     val rule = createComposeRule()
 
+    private val tag = "TextFieldTestTag"
+
     private var defaultDensity = Density(1f)
 
     @Test
     fun textField_typedEvents() {
         keysSequenceTest {
-            Key.H.downAndUp()
-            Key.I.downAndUp(KeyEvent.META_SHIFT_ON)
+            pressKey(Key.H)
+            press(Key.ShiftLeft + Key.I)
             expectedText("hI")
         }
     }
@@ -74,12 +79,14 @@
     @Ignore // re-enable after copy-cut-paste is supported
     @Test
     fun textField_copyPaste() {
-        keysSequenceTest(initText = "hello") {
-            Key.A.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.C.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.DirectionRight.downAndUp()
-            Key.Spacebar.downAndUp()
-            Key.V.downAndUp(KeyEvent.META_CTRL_ON)
+        keysSequenceTest("hello") {
+            withKeyDown(Key.CtrlLeft) {
+                pressKey(Key.A)
+                pressKey(Key.C)
+            }
+            pressKey(Key.DirectionRight)
+            pressKey(Key.Spacebar)
+            press(Key.CtrlLeft + Key.V)
             expectedText("hello hello")
         }
     }
@@ -87,13 +94,13 @@
     @Ignore // re-enable after copy-cut-paste is supported
     @Test
     fun textField_directCopyPaste() {
-        keysSequenceTest(initText = "hello") {
-            Key.A.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Copy.downAndUp()
+        keysSequenceTest("hello") {
+            press(Key.CtrlLeft + Key.A)
+            pressKey(Key.Copy)
             expectedText("hello")
-            Key.DirectionRight.downAndUp()
-            Key.Spacebar.downAndUp()
-            Key.Paste.downAndUp()
+            pressKey(Key.DirectionRight)
+            pressKey(Key.Spacebar)
+            pressKey(Key.Paste)
             expectedText("hello hello")
         }
     }
@@ -101,223 +108,302 @@
     @Ignore // re-enable after copy-cut-paste is supported
     @Test
     fun textField_directCutPaste() {
-        keysSequenceTest(initText = "hello") {
-            Key.A.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Cut.downAndUp()
+        keysSequenceTest("hello") {
+            press(Key.CtrlLeft + Key.A)
+            pressKey(Key.Cut)
             expectedText("")
-            Key.Paste.downAndUp()
+            pressKey(Key.Paste)
             expectedText("hello")
         }
     }
 
     @Test
     fun textField_linesNavigation() {
-        keysSequenceTest(initText = "hello\nworld") {
-            Key.DirectionDown.downAndUp()
-            Key.A.downAndUp()
-            Key.DirectionUp.downAndUp()
-            Key.A.downAndUp()
+        keysSequenceTest("hello\nworld") {
+            pressKey(Key.DirectionDown)
+            pressKey(Key.A)
+            pressKey(Key.DirectionUp)
+            pressKey(Key.A)
             expectedText("haello\naworld")
-            Key.DirectionUp.downAndUp()
-            Key.A.downAndUp()
+            pressKey(Key.DirectionUp)
+            pressKey(Key.A)
             expectedText("ahaello\naworld")
         }
     }
 
     @Test
     fun textField_linesNavigation_cache() {
-        keysSequenceTest(initText = "hello\n\nworld") {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionDown.downAndUp()
-            Key.DirectionDown.downAndUp()
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello\n\nworld") {
+            pressKey(Key.DirectionRight)
+            pressKey(Key.DirectionDown)
+            pressKey(Key.DirectionDown)
+            pressKey(Key.Zero)
             expectedText("hello\n\nw0orld")
         }
     }
 
     @Test
     fun textField_newLine() {
-        keysSequenceTest(initText = "hello") {
-            Key.Enter.downAndUp()
+        keysSequenceTest("hello") {
+            pressKey(Key.Enter)
             expectedText("\nhello")
         }
     }
 
     @Test
     fun textField_backspace() {
-        keysSequenceTest(initText = "hello") {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp()
-            Key.Backspace.downAndUp()
+        keysSequenceTest("hello") {
+            pressKey(Key.DirectionRight)
+            pressKey(Key.DirectionRight)
+            pressKey(Key.Backspace)
             expectedText("hllo")
         }
     }
 
     @Test
     fun textField_delete() {
-        keysSequenceTest(initText = "hello") {
-            Key.Delete.downAndUp()
+        keysSequenceTest("hello") {
+            pressKey(Key.Delete)
             expectedText("ello")
         }
     }
 
     @Test
     fun textField_delete_atEnd() {
-        val text = "hello"
-        val state = TextFieldState(
-            TextFieldValue(
-                text,
-                // Place cursor at end.
-                selection = TextRange(text.length)
-            )
-        )
-        keysSequenceTest(state = state) {
-            Key.Delete.downAndUp()
+        keysSequenceTest("hello", TextRange(5)) {
+            pressKey(Key.Delete)
             expectedText("hello")
         }
     }
 
     @Test
     fun textField_delete_whenEmpty() {
-        keysSequenceTest(initText = "") {
-            Key.Delete.downAndUp()
+        keysSequenceTest {
+            pressKey(Key.Delete)
             expectedText("")
         }
     }
 
     @Test
     fun textField_nextWord() {
-        keysSequenceTest(initText = "hello world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello world") {
+            press(Key.CtrlLeft + Key.DirectionRight)
+            pressKey(Key.Zero)
             expectedText("hello0 world")
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+            press(Key.CtrlLeft + Key.DirectionRight)
+            pressKey(Key.Zero)
             expectedText("hello0 world0")
         }
     }
 
     @Test
     fun textField_nextWord_doubleSpace() {
-        keysSequenceTest(initText = "hello  world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello  world") {
+            press(Key.CtrlLeft + Key.DirectionRight)
+            pressKey(Key.DirectionRight)
+            press(Key.CtrlLeft + Key.DirectionRight)
+            pressKey(Key.Zero)
             expectedText("hello  world0")
         }
     }
 
     @Test
     fun textField_prevWord() {
-        keysSequenceTest(initText = "hello world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.DirectionLeft.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello world") {
+            withKeyDown(Key.CtrlLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionLeft)
+            }
+            pressKey(Key.Zero)
             expectedText("hello 0world")
         }
     }
 
     @Test
     fun textField_HomeAndEnd() {
-        keysSequenceTest(initText = "hello world") {
-            Key.MoveEnd.downAndUp()
-            Key.Zero.downAndUp()
-            Key.MoveHome.downAndUp()
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello world") {
+            pressKey(Key.MoveEnd)
+            pressKey(Key.Zero)
+            pressKey(Key.MoveHome)
+            pressKey(Key.Zero)
             expectedText("0hello world0")
         }
     }
 
     @Test
     fun textField_byWordSelection() {
-        keysSequenceTest(initText = "hello  world\nhi") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON or KeyEvent.META_CTRL_ON)
-            expectedSelection(TextRange(0, 5))
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON or KeyEvent.META_CTRL_ON)
-            expectedSelection(TextRange(0, 12))
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON or KeyEvent.META_CTRL_ON)
-            expectedSelection(TextRange(0, 15))
-            Key.DirectionLeft.downAndUp(KeyEvent.META_SHIFT_ON or KeyEvent.META_CTRL_ON)
-            expectedSelection(TextRange(0, 13))
+        keysSequenceTest("hello  world\nhi") {
+            withKeysDown(listOf(Key.ShiftLeft, Key.CtrlLeft)) {
+                pressKey(Key.DirectionRight)
+                expectedSelection(TextRange(0, 5))
+                pressKey(Key.DirectionRight)
+                expectedSelection(TextRange(0, 12))
+                pressKey(Key.DirectionRight)
+                expectedSelection(TextRange(0, 15))
+                pressKey(Key.DirectionLeft)
+                expectedSelection(TextRange(0, 13))
+            }
+        }
+    }
+
+    @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+    @Test
+    fun textField_lineEndStart() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            pressKey(Key.MoveEnd)
+            pressKey(Key.DirectionRight)
+            pressKey(Key.Zero)
+            expectedText("hi\n0hello world\nhi")
+            pressKey(Key.MoveEnd)
+            pressKey(Key.Zero)
+            expectedText("hi\n0hello world0\nhi")
+            withKeyDown(Key.ShiftLeft) { pressKey(Key.MoveHome) }
+            expectedSelection(TextRange(16, 3))
+            pressKey(Key.MoveHome)
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) { pressKey(Key.MoveEnd) }
+            expectedSelection(TextRange(4, 16))
+            expectedText("hi\n0hello world0\nhi")
+        }
+    }
+
+    @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+    @Test
+    fun textField_altLineLeftRight() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            withKeyDown(Key.AltLeft) { pressKey(Key.DirectionRight) }
+            pressKey(Key.DirectionRight)
+            pressKey(Key.Zero)
+            expectedText("hi\n0hello world\nhi")
+            withKeyDown(Key.AltLeft) { pressKey(Key.DirectionRight) }
+            pressKey(Key.Zero)
+            expectedText("hi\n0hello world0\nhi")
+            withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionLeft) }
+            expectedSelection(TextRange(16, 3))
+            withKeyDown(Key.AltLeft) { pressKey(Key.DirectionLeft) }
+            pressKey(Key.DirectionRight)
+            withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionRight) }
+            expectedSelection(TextRange(4, 16))
+            expectedText("hi\n0hello world0\nhi")
+        }
+    }
+
+    @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
+    @Test
+    fun textField_altTop() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            pressKey(Key.MoveEnd)
+            repeat(3) { pressKey(Key.DirectionRight) }
+            pressKey(Key.Zero)
+            expectedText("hi\nhe0llo world\nhi")
+            withKeyDown(Key.AltLeft) { pressKey(Key.DirectionUp) }
+            pressKey(Key.Zero)
+            expectedText("0hi\nhe0llo world\nhi")
+            pressKey(Key.MoveEnd)
+            repeat(3) { pressKey(Key.DirectionRight) }
+            withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionUp) }
+            expectedSelection(TextRange(6, 0))
+            expectedText("0hi\nhe0llo world\nhi")
         }
     }
 
     @Test
-    fun textField_lineEndStart() {
-        keysSequenceTest(initText = "hello world\nhi") {
-            Key.MoveEnd.downAndUp()
-            Key.Zero.downAndUp()
-            expectedText("hello world0\nhi")
-            Key.MoveEnd.downAndUp()
-            Key.MoveHome.downAndUp()
-            Key.Zero.downAndUp()
-            expectedText("0hello world0\nhi")
-            Key.MoveEnd.downAndUp(KeyEvent.META_SHIFT_ON)
-            expectedSelection(TextRange(1, 16))
+    fun textField_altBottom() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            pressKey(Key.MoveEnd)
+            repeat(3) { pressKey(Key.DirectionRight) }
+            pressKey(Key.Zero)
+            expectedText("hi\nhe0llo world\nhi")
+            withKeysDown(listOf(Key.ShiftLeft, Key.AltLeft)) { pressKey(Key.DirectionDown) }
+            expectedSelection(TextRange(6, 18))
+            pressKey(Key.DirectionLeft)
+            pressKey(Key.Zero)
+            expectedText("hi\nhe00llo world\nhi")
+            withKeyDown(Key.AltLeft) { pressKey(Key.DirectionDown) }
+            pressKey(Key.Zero)
+            expectedText("hi\nhe00llo world\nhi0")
         }
     }
 
     @Test
     fun textField_deleteWords() {
-        keysSequenceTest(initText = "hello world\nhi world") {
-            Key.MoveEnd.downAndUp()
-            Key.Backspace.downAndUp(KeyEvent.META_CTRL_ON)
-            expectedText("hello \nhi world")
-            Key.Delete.downAndUp(KeyEvent.META_CTRL_ON)
+        keysSequenceTest("hello world\nhi world") {
+            pressKey(Key.MoveEnd)
+            withKeyDown(Key.CtrlLeft) {
+                pressKey(Key.Backspace)
+                expectedText("hello \nhi world")
+                pressKey(Key.Delete)
+            }
             expectedText("hello  world")
         }
     }
 
     @Test
     fun textField_deleteToBeginningOfLine() {
-        keysSequenceTest(initText = "hello world\nhi world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Backspace.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText(" world\nhi world")
-            Key.Backspace.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText(" world\nhi world")
-            repeat(3) { Key.DirectionRight.downAndUp() }
-            Key.Backspace.downAndUp(KeyEvent.META_ALT_ON)
+        keysSequenceTest("hello world\nhi world") {
+            press(Key.CtrlLeft + Key.DirectionRight)
+
+            withKeyDown(Key.AltLeft) {
+                pressKey(Key.Backspace)
+                expectedText(" world\nhi world")
+                pressKey(Key.Backspace)
+                expectedText(" world\nhi world")
+            }
+
+            repeat(3) { pressKey(Key.DirectionRight) }
+
+            press(Key.AltLeft + Key.Backspace)
             expectedText("rld\nhi world")
-            Key.DirectionDown.downAndUp()
-            Key.MoveEnd.downAndUp()
-            Key.Backspace.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("rld\n")
-            Key.Backspace.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("rld\n")
+            pressKey(Key.DirectionDown)
+            pressKey(Key.MoveEnd)
+
+            withKeyDown(Key.AltLeft) {
+                pressKey(Key.Backspace)
+                expectedText("rld\n")
+                pressKey(Key.Backspace)
+                expectedText("rld\n")
+            }
         }
     }
 
     @Test
     fun textField_deleteToEndOfLine() {
-        keysSequenceTest(initText = "hello world\nhi world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Delete.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("hello\nhi world")
-            Key.Delete.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("hello\nhi world")
-            repeat(3) { Key.DirectionRight.downAndUp() }
-            Key.Delete.downAndUp(KeyEvent.META_ALT_ON)
+        keysSequenceTest("hello world\nhi world") {
+            press(Key.CtrlLeft + Key.DirectionRight)
+            withKeyDown(Key.AltLeft) {
+                pressKey(Key.Delete)
+                expectedText("hello\nhi world")
+                pressKey(Key.Delete)
+                expectedText("hello\nhi world")
+            }
+
+            repeat(3) { pressKey(Key.DirectionRight) }
+
+            press(Key.AltLeft + Key.Delete)
             expectedText("hello\nhi")
-            Key.MoveHome.downAndUp()
-            Key.Delete.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("hello\n")
-            Key.Delete.downAndUp(KeyEvent.META_ALT_ON)
-            expectedText("hello\n")
+
+            pressKey(Key.MoveHome)
+            withKeyDown(Key.AltLeft) {
+                pressKey(Key.Delete)
+                expectedText("hello\n")
+                pressKey(Key.Delete)
+                expectedText("hello\n")
+            }
         }
     }
 
     @Test
     fun textField_paragraphNavigation() {
-        keysSequenceTest(initText = "hello world\nhi") {
-            Key.DirectionDown.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+        keysSequenceTest("hello world\nhi") {
+            press(Key.CtrlLeft + Key.DirectionDown)
+            pressKey(Key.Zero)
             expectedText("hello world0\nhi")
-            Key.DirectionDown.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.DirectionUp.downAndUp(KeyEvent.META_CTRL_ON)
-            Key.Zero.downAndUp()
+            withKeyDown(Key.CtrlLeft) {
+                pressKey(Key.DirectionDown)
+                pressKey(Key.DirectionUp)
+            }
+            pressKey(Key.Zero)
             expectedText("hello world0\n0hi")
         }
     }
@@ -325,94 +411,140 @@
     @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
     @Test
     fun textField_selectionCaret() {
-        keysSequenceTest(initText = "hello world") {
-            Key.DirectionRight.downAndUp(KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON)
+        keysSequenceTest("hello world") {
+            press(Key.CtrlLeft + Key.ShiftLeft + Key.DirectionRight)
             expectedSelection(TextRange(0, 5))
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
+            press(Key.ShiftLeft + Key.DirectionRight)
             expectedSelection(TextRange(0, 6))
-            Key.Backslash.downAndUp(KeyEvent.META_CTRL_ON)
+            press(Key.CtrlLeft + Key.Backslash)
             expectedSelection(TextRange(6, 6))
-            Key.DirectionLeft.downAndUp(KeyEvent.META_CTRL_ON or KeyEvent.META_SHIFT_ON)
+            press(Key.CtrlLeft + Key.ShiftLeft + Key.DirectionLeft)
             expectedSelection(TextRange(6, 0))
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
+            press(Key.ShiftLeft + Key.DirectionRight)
             expectedSelection(TextRange(1, 6))
         }
     }
 
-    @Ignore // (b/276789499) Ignore for now
     @Test
-    fun textField_pageNavigation() {
+    fun textField_pageNavigationDown() {
         keysSequenceTest(
-            initText = "1\n2\n3\n4\n5",
-            modifier = Modifier.requiredSize(77.dp)
+            initText = "A\nB\nC\nD\nE",
+            modifier = Modifier.requiredSize(73.dp)
         ) {
-            // By page down, the cursor should be at the visible top line. In this case the height
-            // constraint is 77dp which covers from 1(30), 2(30) and middle of 3(17). Thus,
-            // by page down, the first line should be 3, and cursor should be the before letter 3,
-            // i.e. index = 4.
-            Key.PageDown.downAndUp()
+            pressKey(Key.PageDown)
             expectedSelection(TextRange(4))
         }
     }
 
     @Test
+    fun textField_pageNavigationDown_exactFit() {
+        keysSequenceTest(
+            initText = "A\nB\nC\nD\nE",
+            modifier = Modifier.requiredSize(90.dp) // exactly 3 lines fit
+        ) {
+            pressKey(Key.PageDown)
+            expectedSelection(TextRange(6))
+        }
+    }
+
+    @Test
+    fun textField_pageNavigationUp() {
+        keysSequenceTest(
+            initText = "A\nB\nC\nD\nE",
+            initSelection = TextRange(8), // just before 5
+            modifier = Modifier.requiredSize(73.dp)
+        ) {
+            pressKey(Key.PageUp)
+            expectedSelection(TextRange(4))
+        }
+    }
+
+    @Test
+    fun textField_pageNavigationUp_exactFit() {
+        keysSequenceTest(
+            initText = "A\nB\nC\nD\nE",
+            initSelection = TextRange(8), // just before 5
+            modifier = Modifier.requiredSize(90.dp) // exactly 3 lines fit
+        ) {
+            pressKey(Key.PageUp)
+            expectedSelection(TextRange(2))
+        }
+    }
+
+    @Test
+    fun textField_pageNavigationUp_cantGoUp() {
+        keysSequenceTest(
+            initText = "1\n2\n3\n4\n5",
+            initSelection = TextRange(0),
+            modifier = Modifier.requiredSize(90.dp)
+        ) {
+            pressKey(Key.PageUp)
+            expectedSelection(TextRange(0))
+        }
+    }
+
+    @Test
     fun textField_tabSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.Tab.downAndUp()
+        keysSequenceTest("text", singleLine = true) {
+            pressKey(Key.Tab)
             expectedText("text") // no change, should try focus change instead
         }
     }
 
     @Test
     fun textField_tabMultiLine() {
-        keysSequenceTest(initText = "text") {
-            Key.Tab.downAndUp()
+        keysSequenceTest("text") {
+            pressKey(Key.Tab)
             expectedText("\ttext")
         }
     }
 
     @Test
     fun textField_shiftTabSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.Tab.downAndUp(metaState = KeyEvent.META_SHIFT_ON)
+        keysSequenceTest("text", singleLine = true) {
+            press(Key.ShiftLeft + Key.Tab)
             expectedText("text") // no change, should try focus change instead
         }
     }
 
     @Test
     fun textField_enterSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.Enter.downAndUp()
+        keysSequenceTest("text", singleLine = true) {
+            pressKey(Key.Enter)
             expectedText("text") // no change, should do ime action instead
         }
     }
 
     @Test
     fun textField_enterMultiLine() {
-        keysSequenceTest(initText = "text") {
-            Key.Enter.downAndUp()
+        keysSequenceTest("text") {
+            pressKey(Key.Enter)
             expectedText("\ntext")
         }
     }
 
     @Test
     fun textField_withActiveSelection_tabSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.Tab.downAndUp()
+        keysSequenceTest("text", singleLine = true) {
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+            }
+            pressKey(Key.Tab)
             expectedText("text") // no change, should try focus change instead
         }
     }
 
     @Test
     fun textField_withActiveSelection_tabMultiLine() {
-        keysSequenceTest(initText = "text") {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.Tab.downAndUp()
+        keysSequenceTest("text") {
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+            }
+            pressKey(Key.Tab)
             expectedText("t\tt")
         }
     }
@@ -420,134 +552,121 @@
     @Ignore // TODO(halilibo): Remove ignore when backing buffer supports reversed selection
     @Test
     fun textField_selectToLeft() {
-        keysSequenceTest(initText = "hello world hello") {
-            Key.MoveEnd.downAndUp()
+        keysSequenceTest("hello world hello") {
+            pressKey(Key.MoveEnd)
             expectedSelection(TextRange(17))
-            Key.DirectionLeft.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionLeft.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionLeft.downAndUp(KeyEvent.META_SHIFT_ON)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionLeft)
+                pressKey(Key.DirectionLeft)
+                pressKey(Key.DirectionLeft)
+            }
             expectedSelection(TextRange(17, 14))
         }
     }
 
     @Test
     fun textField_withActiveSelection_shiftTabSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.Tab.downAndUp(metaState = KeyEvent.META_SHIFT_ON)
+        keysSequenceTest("text", singleLine = true) {
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+                pressKey(Key.Tab)
+            }
             expectedText("text") // no change, should try focus change instead
         }
     }
 
     @Test
     fun textField_withActiveSelection_enterSingleLine() {
-        keysSequenceTest(initText = "text", singleLine = true) {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.Enter.downAndUp()
+        keysSequenceTest("text", singleLine = true) {
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+            }
+            pressKey(Key.Enter)
             expectedText("text") // no change, should do ime action instead
         }
     }
 
     @Test
     fun textField_withActiveSelection_enterMultiLine() {
-        keysSequenceTest(initText = "text") {
-            Key.DirectionRight.downAndUp()
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.DirectionRight.downAndUp(KeyEvent.META_SHIFT_ON)
-            Key.Enter.downAndUp()
+        keysSequenceTest("text") {
+            pressKey(Key.DirectionRight)
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.DirectionRight)
+                pressKey(Key.DirectionRight)
+            }
+            pressKey(Key.Enter)
             expectedText("t\nt")
         }
     }
 
     private inner class SequenceScope(
         val state: TextFieldState,
-        val nodeGetter: () -> SemanticsNodeInteraction
-    ) {
-        fun Key.downAndUp(metaState: Int = 0) {
-            this.down(metaState)
-            this.up(metaState)
+        private val keyInjectionScope: KeyInjectionScope
+    ) : KeyInjectionScope by keyInjectionScope {
+
+        fun press(keys: List<Key>) {
+            require(keys.isNotEmpty()) { "At least one key must be specified for press action" }
+            if (keys.size == 1) {
+                pressKey(keys.first())
+            } else {
+                withKeysDown(keys.dropLast(1)) { pressKey(keys.last()) }
+            }
         }
 
-        fun Key.down(metaState: Int = 0) {
-            nodeGetter().performKeyPress(downEvent(this, metaState))
-        }
-
-        fun Key.up(metaState: Int = 0) {
-            nodeGetter().performKeyPress(upEvent(this, metaState))
+        infix operator fun Key.plus(other: Key): MutableList<Key> {
+            return mutableListOf(this, other)
         }
 
         fun expectedText(text: String) {
             rule.runOnIdle {
-                Truth.assertThat(state.value.text).isEqualTo(text)
+                assertThat(state.text.toString()).isEqualTo(text)
             }
         }
 
         fun expectedSelection(selection: TextRange) {
             rule.runOnIdle {
-                Truth.assertThat(state.value.selection).isEqualTo(selection)
+                assertThat(state.text.selectionInChars).isEqualTo(selection)
             }
         }
     }
 
     private fun keysSequenceTest(
         initText: String = "",
+        initSelection: TextRange = TextRange.Zero,
         modifier: Modifier = Modifier.fillMaxSize(),
         singleLine: Boolean = false,
         sequence: SequenceScope.() -> Unit,
     ) {
-        val state = TextFieldState(TextFieldValue(initText))
-        keysSequenceTest(
-            state = state,
-            modifier = modifier,
-            singleLine = singleLine,
-            sequence = sequence
-        )
-    }
-
-    private fun keysSequenceTest(
-        state: TextFieldState,
-        modifier: Modifier = Modifier.fillMaxSize(),
-        singleLine: Boolean = false,
-        sequence: SequenceScope.() -> Unit,
-    ) {
-        val inputService = TextInputService(mock())
+        val state = TextFieldState(initText, initSelection)
         val focusRequester = FocusRequester()
         rule.setContent {
             LocalClipboardManager.current.setText(AnnotatedString("InitialTestText"))
-            CompositionLocalProvider(
-                LocalTextInputService provides inputService,
-                LocalDensity provides defaultDensity
-            ) {
+            CompositionLocalProvider(LocalDensity provides defaultDensity) {
                 BasicTextField2(
                     state = state,
                     textStyle = TextStyle(
                         fontFamily = TEST_FONT_FAMILY,
                         fontSize = 30.sp
                     ),
-                    modifier = modifier.focusRequester(focusRequester),
-                    maxLines = if (singleLine) 1 else Int.MAX_VALUE,
+                    modifier = modifier
+                        .focusRequester(focusRequester)
+                        .testTag(tag),
+                    lineLimits = if (singleLine) SingleLine else MultiLine(),
                 )
             }
         }
 
         rule.runOnIdle { focusRequester.requestFocus() }
 
-        sequence(SequenceScope(state) { rule.onNode(hasSetTextAction()) })
+        rule.waitForIdle()
+        rule.mainClock.advanceTimeBy(1000)
+
+        rule.onNodeWithTag(tag).performKeyInput {
+            sequence(SequenceScope(state, this@performKeyInput))
+        }
     }
-}
-
-private fun downEvent(key: Key, metaState: Int = 0): androidx.compose.ui.input.key.KeyEvent {
-    return androidx.compose.ui.input.key.KeyEvent(
-        KeyEvent(0L, 0L, KeyEvent.ACTION_DOWN, key.nativeKeyCode, 0, metaState)
-    )
-}
-
-private fun upEvent(key: Key, metaState: Int = 0): androidx.compose.ui.input.key.KeyEvent {
-    return androidx.compose.ui.input.key.KeyEvent(
-        KeyEvent(0L, 0L, KeyEvent.ACTION_UP, key.nativeKeyCode, 0, metaState)
-    )
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt
index b980b58..0ceebb2 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyboardActionsTest.kt
@@ -28,6 +28,8 @@
 import androidx.compose.foundation.text.KeyboardHelper
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.foundation.text2.input.internal.AndroidTextInputAdapter
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -51,6 +53,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -186,6 +189,7 @@
         rule.onNodeWithTag("box1").assertIsFocused()
     }
 
+    @SdkSuppress(minSdkVersion = 23)
     @Test
     fun textField_performsDefaultBehavior_forDone() {
         rule.setContent {
@@ -347,7 +351,7 @@
                 keyboardActions = KeyboardActionsAll {
                     calledFor = it
                 },
-                maxLines = 1
+                lineLimits = SingleLine
             )
         }
 
@@ -368,7 +372,8 @@
                 keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
                 keyboardActions = KeyboardActionsAll {
                     calledFor = it
-                }
+                },
+                lineLimits = MultiLine(maxHeightInLines = 1)
             )
         }
 
@@ -392,7 +397,7 @@
                 BasicTextField2(
                     state = TextFieldState(),
                     keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
-                    maxLines = 1
+                    lineLimits = SingleLine
                 )
                 Box(
                     Modifier
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt
index fcb76cc..5285a66 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldScrollTest.kt
@@ -26,6 +26,10 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
@@ -59,7 +63,6 @@
 import androidx.compose.ui.test.swipeRight
 import androidx.compose.ui.test.swipeUp
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
@@ -200,7 +203,7 @@
                         state = TextFieldState(longText),
                         modifier = Modifier.size(textFieldSize.toDp()),
                         scrollState = rememberScrollState(),
-                        isVertical = false
+                        lineLimits = SingleLine
                     )
                 }
             }
@@ -234,7 +237,7 @@
                         state = TextFieldState(longText),
                         modifier = Modifier.size(textFieldSize.toDp()),
                         scrollState = rememberScrollState(),
-                        isVertical = true
+                        lineLimits = MultiLine()
                     )
                 }
             }
@@ -318,7 +321,7 @@
                 state = TextFieldState(longText),
                 modifier = Modifier.size(width = 300.dp, height = 50.dp),
                 scrollState = scrollState!!,
-                isVertical = false
+                lineLimits = SingleLine
             )
         }
 
@@ -351,9 +354,8 @@
             ScrollableContent(
                 state = TextFieldState(longText),
                 scrollState = if (stateToggle) scrollState1 else scrollState2,
-                isVertical = false,
                 modifier = Modifier.size(width = 300.dp, height = 50.dp),
-                maxLines = 1
+                lineLimits = SingleLine
             )
         }
 
@@ -389,16 +391,18 @@
             ScrollableContent(
                 state = state,
                 scrollState = scrollState,
-                isVertical = false,
                 modifier = Modifier.size(width = 300.dp, height = 50.dp),
-                maxLines = 1
+                lineLimits = SingleLine
             )
         }
 
         rule.onNodeWithTag(TextfieldTag).assertIsNotFocused()
 
         // move cursor to the end
-        state.editProcessor.reset(state.value.copy(selection = TextRange(longText.length)))
+        // TODO
+        state.editProcessor.reset(
+            TextFieldCharSequence(state.text, selection = TextRange(longText.length))
+        )
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(0)
@@ -413,16 +417,17 @@
             ScrollableContent(
                 state = state,
                 scrollState = scrollState,
-                isVertical = false,
                 modifier = Modifier.size(width = 300.dp, height = 50.dp),
-                maxLines = 1
+                lineLimits = SingleLine
             )
         }
 
         rule.onNodeWithTag(TextfieldTag).performSemanticsAction(SemanticsActions.RequestFocus)
 
         // move cursor to the end
-        state.editProcessor.reset(state.value.copy(selection = TextRange(longText.length)))
+        state.editProcessor.reset(
+            TextFieldCharSequence(state.text, selection = TextRange(longText.length))
+        )
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(scrollState.maxValue)
@@ -431,15 +436,14 @@
 
     @Test
     fun textFieldDoesNotFollowCursor_whenScrollStateChanges_butCursorRemainsTheSame() {
-        val state = TextFieldState(TextFieldValue(longText, selection = TextRange(5)))
+        val state = TextFieldState(longText, initialSelectionInChars = TextRange(5))
         val scrollState = ScrollState(0)
         rule.setContent {
             ScrollableContent(
                 state = state,
                 scrollState = scrollState,
-                isVertical = false,
                 modifier = Modifier.size(width = 300.dp, height = 50.dp),
-                maxLines = 1
+                lineLimits = SingleLine
             )
         }
 
@@ -450,7 +454,7 @@
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(scrollState.maxValue)
-            assertThat(state.value.selection).isEqualTo(TextRange(5))
+            assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
         }
     }
 
@@ -507,7 +511,7 @@
                     state = TextFieldState(text),
                     modifier = Modifier.size(size, height),
                     scrollState = textFieldScrollState,
-                    isVertical = true
+                    lineLimits = MultiLine()
                 )
                 Box(Modifier.size(size))
                 Box(Modifier.size(size))
@@ -549,9 +553,8 @@
                 ScrollableContent(
                     state = state,
                     scrollState = scrollState,
-                    isVertical = false,
                     modifier = modifier,
-                    maxLines = 1
+                    lineLimits = SingleLine
                 )
             }
         }
@@ -570,9 +573,8 @@
                 ScrollableContent(
                     state = state,
                     scrollState = scrollState,
-                    isVertical = true,
                     modifier = modifier,
-                    maxLines = maxLines
+                    lineLimits = MultiLine(maxHeightInLines = maxLines)
                 )
             }
         }
@@ -583,11 +585,9 @@
         modifier: Modifier,
         state: TextFieldState,
         scrollState: ScrollState,
-        isVertical: Boolean,
-        maxLines: Int = Int.MAX_VALUE
+        lineLimits: TextFieldLineLimits
     ) {
         val textLayoutResultRef: Ref<TextLayoutResultProxy?> = remember { Ref() }
-        val resolvedMaxLines = if (isVertical) maxLines else 1
 
         testScope = rememberCoroutineScope()
         BasicTextField2(
@@ -596,7 +596,7 @@
             onTextLayout = {
                 textLayoutResultRef.value = TextLayoutResultProxy(it)
             },
-            maxLines = resolvedMaxLines,
+            lineLimits = lineLimits,
             modifier = modifier.testTag(TextfieldTag)
         )
     }
@@ -608,7 +608,4 @@
             job.join()
         }
     }
-}
-
-@OptIn(ExperimentalFoundationApi::class)
-private fun TextFieldState(text: String) = TextFieldState(TextFieldValue(text))
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt
index 6947fde..cae64e7 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldStateRestorationTest.kt
@@ -64,8 +64,8 @@
         restorationTester.emulateSavedInstanceStateRestore()
 
         rule.runOnIdle {
-            assertThat(restoredState.value.text).isEqualTo("hello, world")
-            assertThat(restoredState.value.selection).isEqualTo(TextRange(0, 12))
+            assertThat(restoredState.text.toString()).isEqualTo("hello, world")
+            assertThat(restoredState.text.selectionInChars).isEqualTo(TextRange(0, 12))
         }
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt
index ff3c7ba..2c65d65 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapterTest.kt
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalFoundationApi::class)
-
 package androidx.compose.foundation.text2.input.internal
 
 import android.text.InputType
 import android.view.inputmethod.EditorInfo
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.text2.input.TextEditFilter
 import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.text.KeyboardHelper
+import androidx.compose.foundation.text2.input.TextEditFilter
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.ui.Modifier
@@ -38,11 +36,12 @@
 import androidx.compose.ui.text.input.ImeOptions
 import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFalse
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -116,7 +115,7 @@
 
     @Test
     fun createInputConnection_modifiesEditorInfo() {
-        val state = TextFieldState(TextFieldValue("hello", selection = TextRange(0, 5)))
+        val state = TextFieldState("hello", initialSelectionInChars = TextRange(0, 5))
         rule.runOnUiThread {
             adapter.startInputSessionWithDefaultsForTest(state)
             val editorInfo = EditorInfo()
@@ -148,8 +147,8 @@
 
             connection.commitText("Hello", 0)
 
-            assertThat(state1.value.text).isEqualTo("")
-            assertThat(state2.value.text).isEqualTo("Hello")
+            assertThat(state1.text.toString()).isEqualTo("")
+            assertThat(state2.text.toString()).isEqualTo("Hello")
         }
     }
 
@@ -297,6 +296,7 @@
         assertThat(keyboardHelper.isSoftwareKeyboardShown()).isTrue()
     }
 
+    @SdkSuppress(minSdkVersion = 23)
     @Test
     fun hideSoftwareKeyboard_fromActiveInputSession_hidesTheKeyboard() {
         var session: TextInputSession? = null
@@ -312,6 +312,16 @@
         assertThat(keyboardHelper.isSoftwareKeyboardShown()).isFalse()
     }
 
+    @Test
+    fun debugMode_isDisabled() {
+        // run this in presubmit to check that we are not accidentally enabling logs on prod
+        assertFalse(
+            TIA_DEBUG,
+            "Oops, looks like you accidentally enabled logging. Don't worry, we've all " +
+                "been there. Just remember to turn it off before you deploy your code."
+        )
+    }
+
     private fun AndroidTextInputAdapter.startInputSessionWithDefaultsForTest(
         state: TextFieldState = TextFieldState(),
         imeOptions: ImeOptions = ImeOptions.Default,
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt
index 67b08b0..dc4fe4c 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/EditorInfoTest.kt
@@ -18,18 +18,20 @@
 
 import android.text.InputType
 import android.view.inputmethod.EditorInfo
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.ImeOptions
 import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalFoundationApi::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class EditorInfoTest {
@@ -530,13 +532,13 @@
     fun initial_selection_info_is_set() {
         val selection = TextRange(1, 2)
         val info = EditorInfo()
-        info.update(TextFieldValue("abc", selection), ImeOptions.Default)
+        info.update(TextFieldCharSequence("abc", selection), ImeOptions.Default)
 
         assertThat(info.initialSelStart).isEqualTo(selection.start)
         assertThat(info.initialSelEnd).isEqualTo(selection.end)
     }
 
     private fun EditorInfo.update(imeOptions: ImeOptions) {
-        this.update(TextFieldValue(), imeOptions)
+        this.update(TextFieldCharSequence(), imeOptions)
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt
index 70d910b..e04e539 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnectionTest.kt
@@ -20,14 +20,15 @@
 import android.view.inputmethod.EditorInfo
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.ImeOptions
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Rule
@@ -46,7 +47,7 @@
     private var activeSession: EditableTextInputSession? = null
 
     private var isOpen: Boolean = true
-    private var value: TextFieldValue = TextFieldValue()
+    private var value: TextFieldCharSequence = TextFieldCharSequence()
     private var imeOptions: ImeOptions = ImeOptions.Default
     private var onRequestEdits: ((List<EditCommand>) -> Unit)? = null
     private var onSendKeyEvent: ((KeyEvent) -> Unit)? = null
@@ -61,7 +62,7 @@
             override val isOpen: Boolean
                 get() = [email protected]
 
-            override val value: TextFieldValue
+            override val value: TextFieldCharSequence
                 get() = [email protected]
 
             override val imeOptions: ImeOptions
@@ -103,7 +104,7 @@
         assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("")
 
         // Set "Hello, World", and place the cursor at the beginning of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange.Zero
         )
@@ -112,7 +113,7 @@
         assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("Hello, World")
 
         // Set "Hello, World", and place the cursor between "H" and "e".
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(1)
         )
@@ -121,7 +122,7 @@
         assertThat(ic.getTextAfterCursor(100, 0)).isEqualTo("ello, World")
 
         // Set "Hello, World", and place the cursor at the end of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(12)
         )
@@ -133,7 +134,7 @@
     @Test
     fun getTextBeforeAndAfterCursorTest_maxCharTest() {
         // Set "Hello, World", and place the cursor at the beginning of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange.Zero
         )
@@ -142,7 +143,7 @@
         assertThat(ic.getTextAfterCursor(5, 0)).isEqualTo("Hello")
 
         // Set "Hello, World", and place the cursor between "H" and "e".
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(1)
         )
@@ -151,7 +152,7 @@
         assertThat(ic.getTextAfterCursor(5, 0)).isEqualTo("ello,")
 
         // Set "Hello, World", and place the cursor at the end of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(12)
         )
@@ -163,7 +164,7 @@
     @Test
     fun getSelectedTextTest() {
         // Set "Hello, World", and place the cursor at the beginning of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange.Zero
         )
@@ -171,7 +172,7 @@
         assertThat(ic.getSelectedText(0)).isNull()
 
         // Set "Hello, World", and place the cursor between "H" and "e".
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(0, 1)
         )
@@ -179,7 +180,7 @@
         assertThat(ic.getSelectedText(0)).isEqualTo("H")
 
         // Set "Hello, World", and place the cursor at the end of the text.
-        value = TextFieldValue(
+        value = TextFieldCharSequence(
             text = "Hello, World",
             selection = TextRange(0, 12)
         )
@@ -195,7 +196,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
 
         // Inserting "Hello, " into the empty text field.
         assertThat(ic.commitText("Hello, ", 1)).isTrue()
@@ -213,7 +214,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
 
         // IME set text "Hello, World." with two commitText API within the single batch session.
         // Do not callback to listener during batch session.
@@ -241,7 +242,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World.", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
 
         // Mark first "H" as composition.
         assertThat(ic.setComposingRegion(0, 1)).isTrue()
@@ -259,7 +260,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -286,7 +287,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
 
         // Inserting "Hello, " into the empty text field.
         assertThat(ic.setComposingText("Hello, ", 1)).isTrue()
@@ -304,7 +305,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
 
         // IME set text "Hello, World." with two setComposingText API within the single batch
         // session. Do not callback to listener during batch session.
@@ -332,7 +333,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World.", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
 
         // Delete first "Hello, " characters
         assertTrue(ic.deleteSurroundingText(0, 6))
@@ -350,7 +351,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -377,7 +378,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World.", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
 
         // Delete first "Hello, " characters
         assertThat(ic.deleteSurroundingTextInCodePoints(0, 6)).isTrue()
@@ -395,7 +396,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -422,7 +423,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World.", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
 
         // Select "Hello, "
         assertThat(ic.setSelection(0, 6)).isTrue()
@@ -440,7 +441,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -467,7 +468,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World.", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World.", selection = TextRange.Zero)
 
         // Cancel any ongoing composition. In this example, there is no composition range, but
         // should record the API call
@@ -486,7 +487,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "Hello, World", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "Hello, World", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -513,7 +514,7 @@
             requestEditsCalled++
             editCommands = it
         }
-        value = TextFieldValue(text = "", selection = TextRange.Zero)
+        value = TextFieldCharSequence(text = "", selection = TextRange.Zero)
 
         // Do not callback to listener during batch session.
         ic.beginBatchEdit()
@@ -641,4 +642,14 @@
 
         assertThat(receivedImeActions).isEqualTo(listOf<ImeAction>())
     }
+
+    @Test
+    fun debugMode_isDisabled() {
+        // run this in presubmit to check that we are not accidentally enabling logs on prod
+        assertFalse(
+            SIC_DEBUG,
+            "Oops, looks like you accidentally enabled logging. Don't worry, we've all " +
+                "been there. Just remember to turn it off before you deploy your code."
+        )
+    }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
index f251e67..523cd75 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
@@ -27,7 +27,6 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
@@ -49,14 +48,13 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
-import org.mockito.kotlin.mock
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
-@OptIn(ExperimentalComposeUiApi::class)
 class HardwareKeyboardTest {
     @get:Rule
     val rule = createComposeRule()
@@ -242,16 +240,77 @@
 
     @Test
     fun textField_lineEndStart() {
-        keysSequenceTest(initText = "hello world\nhi") {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            Key.MoveEnd.downAndUp()
+            Key.DirectionRight.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("hi\n0hello world\nhi")
             Key.MoveEnd.downAndUp()
             Key.Zero.downAndUp()
-            expectedText("hello world0\nhi")
-            Key.MoveEnd.downAndUp()
+            expectedText("hi\n0hello world0\nhi")
+            Key.MoveHome.downAndUp(META_SHIFT_ON)
+            expectedSelection(TextRange(16, 3))
             Key.MoveHome.downAndUp()
-            Key.Zero.downAndUp()
-            expectedText("0hello world0\nhi")
+            Key.DirectionRight.downAndUp()
             Key.MoveEnd.downAndUp(META_SHIFT_ON)
-            expectedSelection(TextRange(1, 16))
+            expectedSelection(TextRange(4, 16))
+            expectedText("hi\n0hello world0\nhi")
+        }
+    }
+
+    @Test
+    fun textField_altLineLeftRight() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            Key.DirectionRight.downAndUp(META_ALT_ON)
+            Key.DirectionRight.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("hi\n0hello world\nhi")
+            Key.DirectionRight.downAndUp(META_ALT_ON)
+            Key.Zero.downAndUp()
+            expectedText("hi\n0hello world0\nhi")
+            Key.DirectionLeft.downAndUp(META_ALT_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(16, 3))
+            Key.DirectionLeft.downAndUp(META_ALT_ON)
+            Key.DirectionRight.downAndUp()
+            Key.DirectionRight.downAndUp(META_ALT_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(4, 16))
+            expectedText("hi\n0hello world0\nhi")
+        }
+    }
+
+    @Test
+    fun textField_altTop() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            Key.MoveEnd.downAndUp()
+            repeat(3) { Key.DirectionRight.downAndUp() }
+            Key.Zero.downAndUp()
+            expectedText("hi\nhe0llo world\nhi")
+            Key.DirectionUp.downAndUp(META_ALT_ON)
+            Key.Zero.downAndUp()
+            expectedText("0hi\nhe0llo world\nhi")
+            Key.MoveEnd.downAndUp()
+            repeat(3) { Key.DirectionRight.downAndUp() }
+            Key.DirectionUp.downAndUp(META_ALT_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(6, 0))
+            expectedText("0hi\nhe0llo world\nhi")
+        }
+    }
+
+    @Test
+    fun textField_altBottom() {
+        keysSequenceTest(initText = "hi\nhello world\nhi") {
+            Key.MoveEnd.downAndUp()
+            repeat(3) { Key.DirectionRight.downAndUp() }
+            Key.Zero.downAndUp()
+            expectedText("hi\nhe0llo world\nhi")
+            Key.DirectionDown.downAndUp(META_ALT_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(6, 18))
+            Key.DirectionLeft.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("hi\nhe00llo world\nhi")
+            Key.DirectionDown.downAndUp(META_ALT_ON)
+            Key.Zero.downAndUp()
+            expectedText("hi\nhe00llo world\nhi0")
         }
     }
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
index c3a20e6e..26dd173 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
@@ -60,6 +60,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.math.ceil
 import kotlin.math.floor
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 
@@ -305,6 +306,7 @@
             )
     }
 
+    @Ignore // b/271927667
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun cursorNotBlinking_whileTyping() = with(rule.density) {
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 eb0efbd..2210e78 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
@@ -16,34 +16,60 @@
 
 package androidx.compose.foundation.text
 
-import android.view.KeyEvent
+import android.view.KeyEvent as AndroidKeyEvent
 import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.isAltPressed
+import androidx.compose.ui.input.key.isShiftPressed
+import androidx.compose.ui.input.key.key
 
-internal actual val platformDefaultKeyMapping = defaultKeyMapping
+internal actual val platformDefaultKeyMapping = object : KeyMapping {
+    override fun map(event: KeyEvent): KeyCommand? = when {
+        event.isShiftPressed && event.isAltPressed ->
+            when (event.key) {
+                MappedKeys.DirectionLeft -> KeyCommand.SELECT_LINE_LEFT
+                MappedKeys.DirectionRight -> KeyCommand.SELECT_LINE_RIGHT
+                MappedKeys.DirectionUp -> KeyCommand.SELECT_HOME
+                MappedKeys.DirectionDown -> KeyCommand.SELECT_END
+                else -> null
+            }
+
+        event.isAltPressed ->
+            when (event.key) {
+                MappedKeys.DirectionLeft -> KeyCommand.LINE_LEFT
+                MappedKeys.DirectionRight -> KeyCommand.LINE_RIGHT
+                MappedKeys.DirectionUp -> KeyCommand.HOME
+                MappedKeys.DirectionDown -> KeyCommand.END
+                else -> null
+            }
+
+        else -> null
+    } ?: defaultKeyMapping.map(event)
+}
 
 internal actual object MappedKeys {
-    actual val A: Key = Key(KeyEvent.KEYCODE_A)
-    actual val C: Key = Key(KeyEvent.KEYCODE_C)
-    actual val H: Key = Key(KeyEvent.KEYCODE_H)
-    actual val V: Key = Key(KeyEvent.KEYCODE_V)
-    actual val Y: Key = Key(KeyEvent.KEYCODE_Y)
-    actual val X: Key = Key(KeyEvent.KEYCODE_X)
-    actual val Z: Key = Key(KeyEvent.KEYCODE_Z)
-    actual val Backslash: Key = Key(KeyEvent.KEYCODE_BACKSLASH)
-    actual val DirectionLeft: Key = Key(KeyEvent.KEYCODE_DPAD_LEFT)
-    actual val DirectionRight: Key = Key(KeyEvent.KEYCODE_DPAD_RIGHT)
-    actual val DirectionUp: Key = Key(KeyEvent.KEYCODE_DPAD_UP)
-    actual val DirectionDown: Key = Key(KeyEvent.KEYCODE_DPAD_DOWN)
-    actual val PageUp: Key = Key(KeyEvent.KEYCODE_PAGE_UP)
-    actual val PageDown: Key = Key(KeyEvent.KEYCODE_PAGE_DOWN)
-    actual val MoveHome: Key = Key(KeyEvent.KEYCODE_MOVE_HOME)
-    actual val MoveEnd: Key = Key(KeyEvent.KEYCODE_MOVE_END)
-    actual val Insert: Key = Key(KeyEvent.KEYCODE_INSERT)
-    actual val Enter: Key = Key(KeyEvent.KEYCODE_ENTER)
-    actual val Backspace: Key = Key(KeyEvent.KEYCODE_DEL)
-    actual val Delete: Key = Key(KeyEvent.KEYCODE_FORWARD_DEL)
-    actual val Paste: Key = Key(KeyEvent.KEYCODE_PASTE)
-    actual val Cut: Key = Key(KeyEvent.KEYCODE_CUT)
-    actual val Copy: Key = Key(KeyEvent.KEYCODE_COPY)
-    actual val Tab: Key = Key(KeyEvent.KEYCODE_TAB)
+    actual val A: Key = Key(AndroidKeyEvent.KEYCODE_A)
+    actual val C: Key = Key(AndroidKeyEvent.KEYCODE_C)
+    actual val H: Key = Key(AndroidKeyEvent.KEYCODE_H)
+    actual val V: Key = Key(AndroidKeyEvent.KEYCODE_V)
+    actual val Y: Key = Key(AndroidKeyEvent.KEYCODE_Y)
+    actual val X: Key = Key(AndroidKeyEvent.KEYCODE_X)
+    actual val Z: Key = Key(AndroidKeyEvent.KEYCODE_Z)
+    actual val Backslash: Key = Key(AndroidKeyEvent.KEYCODE_BACKSLASH)
+    actual val DirectionLeft: Key = Key(AndroidKeyEvent.KEYCODE_DPAD_LEFT)
+    actual val DirectionRight: Key = Key(AndroidKeyEvent.KEYCODE_DPAD_RIGHT)
+    actual val DirectionUp: Key = Key(AndroidKeyEvent.KEYCODE_DPAD_UP)
+    actual val DirectionDown: Key = Key(AndroidKeyEvent.KEYCODE_DPAD_DOWN)
+    actual val PageUp: Key = Key(AndroidKeyEvent.KEYCODE_PAGE_UP)
+    actual val PageDown: Key = Key(AndroidKeyEvent.KEYCODE_PAGE_DOWN)
+    actual val MoveHome: Key = Key(AndroidKeyEvent.KEYCODE_MOVE_HOME)
+    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 Backspace: Key = Key(AndroidKeyEvent.KEYCODE_DEL)
+    actual val Delete: Key = Key(AndroidKeyEvent.KEYCODE_FORWARD_DEL)
+    actual val Paste: Key = Key(AndroidKeyEvent.KEYCODE_PASTE)
+    actual val Cut: Key = Key(AndroidKeyEvent.KEYCODE_CUT)
+    actual val Copy: Key = Key(AndroidKeyEvent.KEYCODE_COPY)
+    actual val Tab: Key = Key(AndroidKeyEvent.KEYCODE_TAB)
 }
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt
new file mode 100644
index 0000000..876eb87
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicSecureTextField.kt
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldState
+import androidx.compose.foundation.text2.input.TextObfuscationMode
+import androidx.compose.foundation.text2.input.mask
+import androidx.compose.foundation.text2.input.then
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.semantics.password
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.unit.Density
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.launch
+
+/**
+ * BasicSecureTextField is a new text input component that is still in heavy development.
+ * We strongly advise against using it in production as its API and implementation are currently
+ * unstable. Many essential features such as selection, cursor, gestures, etc. may not work
+ * correctly or may not even exist yet.
+ *
+ * BasicSecureTextField is specifically designed for password entry fields and is a preconfigured
+ * alternative to BasicTextField2. It only supports a single line of content and comes with default
+ * settings for KeyboardOptions, filter, and codepointTransformation that are appropriate for
+ * entering secure content. Additionally, some context menu actions like cut, copy, and drag are
+ * disabled for added security.
+ *
+ * @param state [TextFieldState] object that holds the internal state of a [BasicTextField2].
+ * @param modifier optional [Modifier] for this text field.
+ * @param enabled controls the enabled state of the [BasicTextField2]. When `false`, the text
+ * field will be neither editable nor focusable, the input of the text field will not be selectable.
+ * @param onSubmit Called when the user submits a form either by pressing the action button in the
+ * input method editor (IME), or by pressing the enter key on a hardware keyboard. If the user
+ * submits the form by pressing the action button in the IME, the provided IME action is passed to
+ * the function. If the user submits the form by pressing the enter key on a hardware keyboard,
+ * the defined [imeAction] parameter is passed to the function. Return true to indicate that the
+ * action has been handled completely, which will skip the default behavior, such as hiding the
+ * keyboard for the [ImeAction.Done] action.
+ * @param imeAction The IME action. This IME action is honored by keyboard and may show specific
+ * icons on the keyboard.
+ * @param textObfuscationMode Determines the method used to obscure the input text.
+ * @param keyboardType The keyboard type to be used in this text field. It is set to
+ * [KeyboardType.Password] by default. Use [KeyboardType.NumberPassword] for numerical password
+ * fields.
+ * @param filter Optional [TextEditFilter] that will be used to filter changes to the
+ * [TextFieldState] made by the user. The filter will be applied to changes made by hardware and
+ * software keyboard events, pasting or dropping text, accessibility services, and tests. The filter
+ * will _not_ be applied when changing the [state] programmatically, or when the filter is changed.
+ * If the filter is changed on an existing text field, it will be applied to the next user edit.
+ * the filter will not immediately affect the current [state].
+ * @param textStyle Style configuration for text content that's displayed in the editor.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this TextField. You can create and pass in your own remembered [MutableInteractionSource]
+ * if you want to observe [Interaction]s and customize the appearance / behavior of this TextField
+ * for different [Interaction]s.
+ * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
+ * provided, there will be no cursor drawn
+ * @param scrollState Used to manage the horizontal scroll when the input content exceeds the
+ * bounds of the text field. It controls the state of the scroll for the text field.
+ * @param onTextLayout Callback that is executed when a new text layout is calculated. A
+ * [TextLayoutResult] object that callback provides contains paragraph information, size of the
+ * text, baselines and other details. The callback can be used to add additional decoration or
+ * functionality to the text. For example, to draw a cursor or selection around the text. [Density]
+ * scope is the one that was used while creating the given text layout.
+ * @param decorationBox Composable lambda that allows to add decorations around text field, such
+ * as icon, placeholder, helper messages or similar, and automatically increase the hit target area
+ * of the text field. To allow you to control the placement of the inner text field relative to your
+ * decorations, the text field implementation will pass in a framework-controlled composable
+ * parameter "innerTextField" to the decorationBox lambda you provide. You must call
+ * innerTextField exactly once.
+ */
+@ExperimentalFoundationApi
+@Composable
+fun BasicSecureTextField(
+    state: TextFieldState,
+    modifier: Modifier = Modifier,
+    onSubmit: ((ImeAction) -> Boolean)? = null,
+    imeAction: ImeAction = ImeAction.Default,
+    textObfuscationMode: TextObfuscationMode = TextObfuscationMode.RevealLastTyped,
+    keyboardType: KeyboardType = KeyboardType.Password,
+    enabled: Boolean = true,
+    filter: TextEditFilter? = null,
+    textStyle: TextStyle = TextStyle.Default,
+    interactionSource: MutableInteractionSource? = null,
+    cursorBrush: Brush = SolidColor(Color.Black),
+    scrollState: ScrollState = rememberScrollState(),
+    onTextLayout: Density.(TextLayoutResult) -> Unit = {},
+    decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
+        @Composable { innerTextField -> innerTextField() }
+) {
+    val coroutineScope = rememberCoroutineScope()
+    val secureTextFieldController = remember(coroutineScope) {
+        SecureTextFieldController(coroutineScope)
+    }
+
+    // revealing last typed character depends on two conditions;
+    // 1 - Requested Obfuscation method
+    // 2 - if the system allows it
+    val revealLastTypedEnabled = textObfuscationMode == TextObfuscationMode.RevealLastTyped
+
+    // while toggling between obfuscation methods if the revealing gets disabled, reset the reveal.
+    if (!revealLastTypedEnabled) {
+        secureTextFieldController.passwordRevealFilter.hide()
+    }
+
+    val codepointTransformation = when {
+        revealLastTypedEnabled -> {
+            secureTextFieldController.codepointTransformation
+        }
+
+        textObfuscationMode == TextObfuscationMode.Hidden -> {
+            CodepointTransformation.mask('\u2022')
+        }
+
+        else -> {
+            CodepointTransformation.None
+        }
+    }
+
+    val secureTextFieldModifier = modifier
+        .semantics(mergeDescendants = true) { password() }
+        .then(
+            if (revealLastTypedEnabled) {
+                secureTextFieldController.focusChangeModifier
+            } else {
+                Modifier
+            }
+        )
+
+    BasicTextField2(
+        state = state,
+        modifier = secureTextFieldModifier,
+        enabled = enabled,
+        readOnly = false,
+        filter = if (revealLastTypedEnabled) {
+            filter?.then(secureTextFieldController.passwordRevealFilter)
+                ?: secureTextFieldController.passwordRevealFilter
+        } else filter,
+        textStyle = textStyle,
+        interactionSource = interactionSource,
+        cursorBrush = cursorBrush,
+        lineLimits = TextFieldLineLimits.SingleLine,
+        scrollState = scrollState,
+        keyboardOptions = KeyboardOptions(
+            autoCorrect = false,
+            keyboardType = keyboardType,
+            imeAction = imeAction
+        ),
+        keyboardActions = onSubmit?.let { KeyboardActions(onSubmit = it) }
+            ?: KeyboardActions.Default,
+        onTextLayout = onTextLayout,
+        codepointTransformation = codepointTransformation,
+        decorationBox = decorationBox,
+    )
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+internal class SecureTextFieldController(
+    coroutineScope: CoroutineScope
+) {
+    /**
+     * A special [TextEditFilter] that tracks changes to the content to identify the last typed
+     * character to reveal. `scheduleHide` lambda is delegated to a member function to be able to
+     * use [passwordRevealFilter] instance.
+     */
+    val passwordRevealFilter = PasswordRevealFilter(::scheduleHide)
+
+    /**
+     * Pass to [BasicTextField2] for obscuring text input.
+     */
+    val codepointTransformation = CodepointTransformation { codepointIndex, codepoint ->
+        if (codepointIndex == passwordRevealFilter.revealCodepointIndex) {
+            // reveal the last typed character by not obscuring it
+            codepoint
+        } else {
+            0x2022
+        }
+    }
+
+    val focusChangeModifier = Modifier.onFocusChanged {
+        if (!it.isFocused) passwordRevealFilter.hide()
+    }
+
+    private val resetTimerSignal = Channel<Unit>(Channel.UNLIMITED)
+
+    init {
+        // start a coroutine that listens for scheduled hide events.
+        coroutineScope.launch {
+            resetTimerSignal.consumeAsFlow()
+                .collectLatest {
+                    delay(LAST_TYPED_CHARACTER_REVEAL_DURATION_MILLIS)
+                    passwordRevealFilter.hide()
+                }
+        }
+    }
+
+    private fun scheduleHide() {
+        // signal the listener that a new hide call is scheduled.
+        val result = resetTimerSignal.trySend(Unit)
+        if (!result.isSuccess) {
+            passwordRevealFilter.hide()
+        }
+    }
+}
+
+/**
+ * Special filter that tracks the changes in a TextField to identify the last typed character and
+ * mark it for reveal in password fields.
+ *
+ * @param scheduleHide A lambda that schedules a [hide] call into future after a new character is
+ * typed.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal class PasswordRevealFilter(
+    val scheduleHide: () -> Unit
+) : TextEditFilter {
+    // TODO: Consider setting this as a tracking annotation in AnnotatedString.
+    internal var revealCodepointIndex by mutableStateOf(-1)
+        private set
+
+    override fun filter(
+        originalValue: TextFieldCharSequence,
+        valueWithChanges: TextFieldBufferWithSelection
+    ) {
+        // We only care about a single character insertion changes
+        val singleCharacterInsertion = valueWithChanges.changes.changeCount == 1 &&
+            valueWithChanges.changes.getRange(0).length == 1 &&
+            valueWithChanges.changes.getOriginalRange(0).length == 0
+
+        // if there is an expanded selection, don't reveal anything
+        if (!singleCharacterInsertion || valueWithChanges.hasSelection) {
+            revealCodepointIndex = -1
+            return
+        }
+
+        val insertionPoint = valueWithChanges.changes.getRange(0).min
+        if (revealCodepointIndex != insertionPoint) {
+            // start the timer for auto hide
+            scheduleHide()
+            revealCodepointIndex = insertionPoint
+        }
+    }
+
+    /**
+     * Removes any revealed character index. Everything goes back into hiding.
+     */
+    fun hide() {
+        revealCodepointIndex = -1
+    }
+}
+
+// adopted from PasswordTransformationMethod from Android platform.
+private const val LAST_TYPED_CHARACTER_REVEAL_DURATION_MILLIS = 1500L
+
+private fun KeyboardActions(onSubmit: (ImeAction) -> Boolean) = KeyboardActions(
+    onDone = { if (!onSubmit(ImeAction.Done)) defaultKeyboardAction(ImeAction.Done) },
+    onGo = { if (!onSubmit(ImeAction.Go)) defaultKeyboardAction(ImeAction.Go) },
+    onNext = { if (!onSubmit(ImeAction.Next)) defaultKeyboardAction(ImeAction.Next) },
+    onPrevious = { if (!onSubmit(ImeAction.Previous)) defaultKeyboardAction(ImeAction.Previous) },
+    onSearch = { if (!onSubmit(ImeAction.Search)) defaultKeyboardAction(ImeAction.Search) },
+    onSend = { if (!onSubmit(ImeAction.Send)) defaultKeyboardAction(ImeAction.Send) },
+)
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
index 19d0edf..4891028 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
@@ -27,19 +27,24 @@
 import androidx.compose.foundation.interaction.collectIsFocusedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.text.DefaultMinLines
 import androidx.compose.foundation.text.InternalFoundationTextApi
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text.TextDelegate
 import androidx.compose.foundation.text.heightInLines
 import androidx.compose.foundation.text.textFieldMinSize
+import androidx.compose.foundation.text2.input.CodepointTransformation
+import androidx.compose.foundation.text2.input.SingleLineCodepointTransformation
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldLineLimits
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.internal.AndroidTextInputPlugin
 import androidx.compose.foundation.text2.input.internal.TextFieldCoreModifier
 import androidx.compose.foundation.text2.input.internal.TextFieldDecoratorModifier
 import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.input.toVisualText
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
@@ -54,6 +59,7 @@
 import androidx.compose.ui.platform.LocalFontFamilyResolver
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalPlatformTextInputPluginRegistry
+import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.ImeAction
@@ -66,7 +72,14 @@
  * using it in production since it has a very unstable API and implementation for the time being.
  * Many core features like selection, cursor, gestures, etc. may fail or simply not exist.
  *
- * @param state [TextFieldState] object that holds the internal state of a [BasicTextField2].
+ * Basic text composable that provides an interactive box that accepts text input through software
+ * or hardware keyboard.
+ *
+ * All the editing state of this composable is hoisted through [state]. Whenever the contents of
+ * this composable change via user input or semantics, [TextFieldState.text] gets updated.
+ * Similarly, all the programmatic updates made to [state] also reflect on this composable.
+ *
+ * @param state [TextFieldState] object that holds the internal editing state of [BasicTextField2].
  * @param modifier optional [Modifier] for this text field.
  * @param enabled controls the enabled state of the [BasicTextField2]. When `false`, the text
  * field will be neither editable nor focusable, the input of the text field will not be selectable.
@@ -79,30 +92,34 @@
  * will _not_ be applied when changing the [state] programmatically, or when the filter is changed.
  * If the filter is changed on an existing text field, it will be applied to the next user edit.
  * the filter will not immediately affect the current [state].
- * @param textStyle Style configuration for text content that's displayed in the editor.
+ * @param textStyle Typographic and graphic style configuration for text content that's displayed
+ * in the editor.
+ * @param keyboardOptions Software keyboard options that contain configurations such as
+ * [KeyboardType] and [ImeAction].
+ * @param keyboardActions When the input service emits an IME action, the corresponding callback
+ * is called. Note that this IME action may be different from what you specified in
+ * [KeyboardOptions.imeAction].
+ * @param lineLimits Whether the text field should be [SingleLine], scroll horizontally, and
+ * ignore newlines; or [MultiLine] and grow and scroll vertically. If [SingleLine] is passed without
+ * specifying the [codepointTransformation] parameter, a [CodepointTransformation] is automatically
+ * applied. This transformation replaces any newline characters ('\n') within the text with regular
+ * whitespace (' '), ensuring that the contents of the text field are presented in a single line.
+ * @param onTextLayout Callback that is executed when a new text layout is calculated. A
+ * [TextLayoutResult] object contains paragraph information, size of the text, baselines and other
+ * details. The callback can be used to add additional decoration or functionality to the text.
+ * For example, to draw a cursor or selection around the text. [Density] scope is the one that was
+ * used while creating the given text layout.
  * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
  * for this TextField. You can create and pass in your own remembered [MutableInteractionSource]
  * if you want to observe [Interaction]s and customize the appearance / behavior of this TextField
  * for different [Interaction]s.
  * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
- * provided, there will be no cursor drawn
- * @param minLines The minimum height in terms of minimum number of visible lines. It is required
- * that 1 <= [minLines] <= [maxLines].
- * @param maxLines The maximum height in terms of maximum number of visible lines. It is required
- * that 1 <= [minLines] <= [maxLines].
+ * provided, then no cursor will be drawn.
  * @param scrollState Scroll state that manages either horizontal or vertical scroll of TextField.
- * If [maxLines] is 1, this TextField is treated as single line which activates horizontal scroll
- * behavior. In other cases TextField becomes vertically scrollable.
- * @param keyboardOptions software keyboard options that contains configuration such as
- * [KeyboardType] and [ImeAction].
- * @param keyboardActions when the input service emits an IME action, the corresponding callback
- * is called. Note that this IME action may be different from what you specified in
- * [KeyboardOptions.imeAction].
- * @param onTextLayout Callback that is executed when a new text layout is calculated. A
- * [TextLayoutResult] object that callback provides contains paragraph information, size of the
- * text, baselines and other details. The callback can be used to add additional decoration or
- * functionality to the text. For example, to draw a cursor or selection around the text. [Density]
- * scope is the one that was used while creating the given text layout.
+ * If [lineLimits] is [SingleLine], this text field is treated as single line with horizontal
+ * scroll behavior. In other cases the text field becomes vertically scrollable.
+ * @param codepointTransformation Visual transformation interface that provides a 1-to-1 mapping of
+ * codepoints.
  * @param decorationBox Composable lambda that allows to add decorations around text field, such
  * as icon, placeholder, helper messages or similar, and automatically increase the hit target area
  * of the text field. To allow you to control the placement of the inner text field relative to your
@@ -122,12 +139,12 @@
     textStyle: TextStyle = TextStyle.Default,
     keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
     keyboardActions: KeyboardActions = KeyboardActions.Default,
-    minLines: Int = DefaultMinLines,
-    maxLines: Int = Int.MAX_VALUE,
+    lineLimits: TextFieldLineLimits = TextFieldLineLimits.Default,
     onTextLayout: Density.(TextLayoutResult) -> Unit = {},
     interactionSource: MutableInteractionSource? = null,
     cursorBrush: Brush = SolidColor(Color.Black),
     scrollState: ScrollState = rememberScrollState(),
+    codepointTransformation: CodepointTransformation? = null,
     decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
         @Composable { innerTextField -> innerTextField() }
 ) {
@@ -138,7 +155,7 @@
     val fontFamilyResolver = LocalFontFamilyResolver.current
     val density = LocalDensity.current
     val layoutDirection = LocalLayoutDirection.current
-    val singleLine = minLines == 1 && maxLines == 1
+    val singleLine = lineLimits == SingleLine
     // We're using this to communicate focus state to cursor for now.
     @Suppress("NAME_SHADOWING")
     val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
@@ -148,7 +165,7 @@
     val textLayoutState = remember {
         TextLayoutState(
             TextDelegate(
-                text = state.value.annotatedString,
+                text = AnnotatedString(state.text.toString()),
                 style = textStyle,
                 density = density,
                 fontFamilyResolver = fontFamilyResolver,
@@ -188,6 +205,16 @@
 
     Box(decorationModifiers) {
         decorationBox(innerTextField = {
+            val minLines: Int
+            val maxLines: Int
+            if (lineLimits is MultiLine) {
+                minLines = lineLimits.minHeightInLines
+                maxLines = lineLimits.maxHeightInLines
+            } else {
+                minLines = 1
+                maxLines = 1
+            }
+
             val coreModifiers = Modifier
                 .heightInLines(
                     textStyle = textStyle,
@@ -210,8 +237,17 @@
 
             Layout(modifier = coreModifiers) { _, constraints ->
                 val result = with(textLayoutState) {
+                    // First prefer provided codepointTransformation if not null, e.g.
+                    // BasicSecureTextField would send Password Transformation.
+                    // Second, apply a SingleLineCodepointTransformation if text field is configured
+                    // to be single line.
+                    // Else, don't apply any visual transformation.
+                    val appliedCodepointTransformation = codepointTransformation
+                         ?: SingleLineCodepointTransformation.takeIf { lineLimits == SingleLine }
+
+                    val visualText = state.text.toVisualText(appliedCodepointTransformation)
                     layout(
-                        text = state.value.annotatedString,
+                        text = AnnotatedString(visualText.toString()),
                         textStyle = textStyle,
                         softWrap = !singleLine,
                         density = density,
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt
index 4db0bc4..ce7b0ad 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/AllCapsFilter.kt
@@ -17,14 +17,17 @@
 package androidx.compose.foundation.text2.input
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.runtime.Stable
-import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.KeyboardCapitalization
 import androidx.compose.ui.text.intl.Locale
 import androidx.compose.ui.text.toUpperCase
 
 /**
  * Returns a [TextEditFilter] that forces all text to be uppercase.
  *
+ * This filter automatically configures the keyboard to capitalize all characters.
+ *
  * @param locale The [Locale] in which to perform the case conversion.
  */
 @ExperimentalFoundationApi
@@ -34,10 +37,21 @@
 // This is a very naive implementation for now, not intended to be production-ready.
 @OptIn(ExperimentalFoundationApi::class)
 private data class AllCapsFilter(private val locale: Locale) : TextEditFilter {
-    override fun filter(oldState: TextFieldValue, newState: MutableTextFieldValueWithSelection) {
-        val selection = newState.selectionInCodepoints
-        newState.replace(0, newState.length, newState.toString().toUpperCase(locale))
-        newState.selectCodepointsIn(selection)
+    override val keyboardOptions = KeyboardOptions(
+        capitalization = KeyboardCapitalization.Characters
+    )
+
+    override fun filter(
+        originalValue: TextFieldCharSequence,
+        valueWithChanges: TextFieldBufferWithSelection
+    ) {
+        val selection = valueWithChanges.selectionInCodepoints
+        valueWithChanges.replace(
+            0,
+            valueWithChanges.length,
+            valueWithChanges.toString().toUpperCase(locale)
+        )
+        valueWithChanges.selectCodepointsIn(selection)
     }
 
     override fun toString(): String = "TextEditFilter.allCaps(locale=$locale)"
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt
new file mode 100644
index 0000000..df7909b
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/CodepointTransformation.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.appendCodePointX
+import androidx.compose.runtime.Stable
+
+/**
+ * Visual transformation interface for input fields.
+ *
+ * This interface is responsible for 1-to-1 mapping of every codepoint in input state to another
+ * codepoint before text is rendered. Visual transformation is useful when the underlying source
+ * of input needs to remain but rendered content should look different, e.g. password obscuring.
+ */
+@ExperimentalFoundationApi
+fun interface CodepointTransformation {
+
+    /**
+     * Transforms a single [codepoint] located at [codepointIndex] to another codepoint.
+     *
+     * A codepoint is an integer that always maps to a single character. Every codepoint in Unicode
+     * is comprised of 16 bits, 2 bytes.
+     */
+    // TODO: add more codepoint explanation or doc referral
+    fun transform(codepointIndex: Int, codepoint: Int): Int
+
+    companion object {
+
+        @Stable
+        val None = CodepointTransformation { _, codepoint -> codepoint }
+    }
+}
+
+/**
+ * Creates a masking [CodepointTransformation] that maps all codepoints to a specific [character].
+ */
+@ExperimentalFoundationApi
+fun CodepointTransformation.Companion.mask(character: Char): CodepointTransformation =
+    MaskCodepointTransformation(character)
+
+@OptIn(ExperimentalFoundationApi::class)
+private class MaskCodepointTransformation(val character: Char) : CodepointTransformation {
+    override fun transform(codepointIndex: Int, codepoint: Int): Int {
+        return character.code
+    }
+
+    override fun toString(): String {
+        return "MaskCodepointTransformation(character=$character)"
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is MaskCodepointTransformation) return false
+
+        if (character != other.character) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        return character.hashCode()
+    }
+}
+
+/**
+ * [CodepointTransformation] that converts all line breaks (\n) into white space(U+0020) and
+ * carriage returns(\r) to zero-width no-break space (U+FEFF). This transformation forces any
+ * content to appear as single line.
+ */
+@OptIn(ExperimentalFoundationApi::class)
+internal object SingleLineCodepointTransformation : CodepointTransformation {
+
+    private const val LINE_FEED = '\n'.code
+    private const val CARRIAGE_RETURN = '\r'.code
+
+    private const val WHITESPACE = ' '.code
+    private const val ZERO_WIDTH_SPACE = '\uFEFF'.code
+
+    override fun transform(codepointIndex: Int, codepoint: Int): Int {
+        if (codepoint == LINE_FEED) return WHITESPACE
+        if (codepoint == CARRIAGE_RETURN) return ZERO_WIDTH_SPACE
+        return codepoint
+    }
+
+    override fun toString(): String {
+        return "SingleLineCodepointTransformation"
+    }
+}
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun CharSequence.toVisualText(
+    codepointTransformation: CodepointTransformation?
+): CharSequence {
+    codepointTransformation ?: return this
+    val text = this
+    return buildString {
+        (0 until Character.codePointCount(text, 0, text.length)).forEach { codepointIndex ->
+            val codepoint = codepointTransformation.transform(
+                codepointIndex, Character.codePointAt(text, codepointIndex)
+            )
+            appendCodePointX(codepoint)
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt
index 301bddc..f4b8ab3 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MaxLengthFilter.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.runtime.Stable
-import androidx.compose.ui.text.input.TextFieldValue
 
 /**
  * Returns [TextEditFilter] that rejects input which causes the total length of the text field to be
@@ -53,10 +52,14 @@
         require(maxLength >= 0) { "maxLength must be at least zero, was $maxLength" }
     }
 
-    override fun filter(oldState: TextFieldValue, newState: MutableTextFieldValueWithSelection) {
-        val newLength = if (inCodepoints) newState.codepointLength else newState.length
+    override fun filter(
+        originalValue: TextFieldCharSequence,
+        valueWithChanges: TextFieldBufferWithSelection
+    ) {
+        val newLength =
+            if (inCodepoints) valueWithChanges.codepointLength else valueWithChanges.length
         if (newLength > maxLength) {
-            newState.resetTo(oldState)
+            valueWithChanges.revertAllChanges()
         }
     }
 
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt
index 2f02be4..fd6592c 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditFilter.kt
@@ -19,8 +19,8 @@
 package androidx.compose.foundation.text2.input
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.runtime.Stable
-import androidx.compose.ui.text.input.TextFieldValue
 
 /**
  * A function that is ran after every change made to a [TextFieldState] by user input and can change
@@ -34,43 +34,65 @@
  * Prebuilt filters are provided for common filter operations. See:
  *  - `TextEditFilter`.[maxLengthInChars]`()`
  *  - `TextEditFilter`.[maxLengthInCodepoints]`()`
+ *  - `TextEditFilter`.[allCaps]`()`
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2CustomFilterSample
  */
 @ExperimentalFoundationApi
 @Stable
 fun interface TextEditFilter {
 
     /**
+     * Optional [KeyboardOptions] that will be used as the default keyboard options for configuring
+     * the IME. The options passed directly to the text field composable will always override this.
+     */
+    val keyboardOptions: KeyboardOptions? get() = null
+
+    /**
      * The filter operation. For more information see the documentation on [TextEditFilter].
      *
-     * @sample androidx.compose.foundation.samples.BasicTextField2CustomFilterSample
+     * To reject all changes in [valueWithChanges], call
+     * `valueWithChanges.`[revertAllChanges][TextFieldBufferWithSelection.revertAllChanges].
      *
-     * @param oldState The value of the field before the change was performed.
-     * @param newState The value of the field after the change. This value can be changed in-place
-     * to alter or reject the changes or set the selection.
+     * @param originalValue The value of the field before the change was performed.
+     * @param valueWithChanges The value of the field after the change. This value can be changed
+     * in-place to alter or reject the changes or set the selection.
      */
-    fun filter(oldState: TextFieldValue, newState: MutableTextFieldValueWithSelection)
+    fun filter(originalValue: TextFieldCharSequence, valueWithChanges: TextFieldBufferWithSelection)
 
     companion object
 }
 
 /**
- * Creates a filter chain that will run [next] after this. Filters are applied in order – [next]
- * will see any the changes made by this filter.
+ * Creates a filter chain that will run [next] after this. Filters are applied sequentially, so any
+ * changes made by this filter will be visible to [next].
  *
  * @sample androidx.compose.foundation.samples.BasicTextField2FilterChainingSample
+ *
+ * @param next The [TextEditFilter] that will be ran after this one.
+ * @param keyboardOptions The [KeyboardOptions] options to use for the chained filter. If not
+ * specified, the chained filter will not specify any [KeyboardOptions], even if one or both of
+ * this or [next] specified some.
  */
 @ExperimentalFoundationApi
 @Stable
-fun TextEditFilter.then(next: TextEditFilter): TextEditFilter = FilterChain(this, next)
+fun TextEditFilter.then(
+    next: TextEditFilter,
+    keyboardOptions: KeyboardOptions? = null
+): TextEditFilter = FilterChain(this, next, keyboardOptions)
 
 private class FilterChain(
     private val first: TextEditFilter,
-    private val second: TextEditFilter
+    private val second: TextEditFilter,
+    override val keyboardOptions: KeyboardOptions?
 ) : TextEditFilter {
 
-    override fun filter(oldState: TextFieldValue, newState: MutableTextFieldValueWithSelection) {
-        first.filter(oldState, newState)
-        second.filter(oldState, newState)
+    override fun filter(
+        originalValue: TextFieldCharSequence,
+        valueWithChanges: TextFieldBufferWithSelection
+    ) {
+        first.filter(originalValue, valueWithChanges)
+        second.filter(originalValue, valueWithChanges)
     }
 
     override fun toString(): String = "$first.then($second)"
@@ -83,6 +105,7 @@
 
         if (first != other.first) return false
         if (second != other.second) return false
+        if (keyboardOptions != other.keyboardOptions) return false
 
         return true
     }
@@ -90,6 +113,7 @@
     override fun hashCode(): Int {
         var result = first.hashCode()
         result = 31 * result + second.hashCode()
+        result = 32 * result + keyboardOptions.hashCode()
         return result
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt
new file mode 100644
index 0000000..93b0021
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextEditResult.kt
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.ui.text.TextRange
+
+/**
+ * A value to be returned from [TextFieldState.edit] that specifies where to place the cursor or
+ * selection.
+ *
+ * Predefined results include:
+ *  - [TextFieldBuffer.placeCursorAtEnd]
+ *  - [TextFieldBuffer.placeCursorBeforeFirstChange]
+ *  - [TextFieldBuffer.placeCursorAfterLastChange]
+ *  - [TextFieldBuffer.placeCursorBeforeCharAt]
+ *  - [TextFieldBuffer.placeCursorAfterCharAt]
+ *  - [TextFieldBuffer.placeCursorBeforeCodepointAt]
+ *  - [TextFieldBuffer.placeCursorAfterCodepointAt]
+ *  - [TextFieldBuffer.selectAll]
+ *  - [TextFieldBuffer.selectAllChanges]
+ *  - [TextFieldBuffer.selectCharsIn]
+ *  - [TextFieldBuffer.selectCodepointsIn]
+ */
+@ExperimentalFoundationApi
+sealed class TextEditResult {
+    /**
+     * Returns the [TextRange] to set as the new selection. If the selection is collapsed, it will
+     * set the cursor instead.
+     *
+     * @return The new range of the selection, in character offsets.
+     */
+    internal abstract fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange
+}
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the codepoint at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
+ * of the field, after the last character, pass index [TextFieldBuffer.codepointLength].
+ *
+ * @param index Codepoint index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see placeCursorBeforeCharAt
+ * @see placeCursorAfterCodepointAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeCodepointAt(index: Int): TextEditResult =
+    PlaceCursorResult(this, index, after = false, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the codepoint at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
+ *
+ * @param index Codepoint index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.codepointLength] (exclusive).
+ *
+ * @see placeCursorBeforeCharAt
+ * @see placeCursorAfterCodepointAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterCodepointAt(index: Int): TextEditResult =
+    PlaceCursorResult(this, index, after = true, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the character at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest earlier index.
+ *
+ * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
+ * of the field, after the last character, pass index [TextFieldBuffer.length] or call
+ * [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor before, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see placeCursorBeforeCodepointAt
+ * @see placeCursorAfterCharAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeCharAt(index: Int): TextEditResult =
+    PlaceCursorResult(this, index, after = false, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the character at the given index.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+ * nearest earlier index.
+ *
+ * To place the cursor at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length] or call [placeCursorAtEnd].
+ *
+ * @param index Character index to place cursor after, should be in range 0 (inclusive) to
+ * [TextFieldBuffer.length] (exclusive).
+ *
+ * @see placeCursorAfterCodepointAt
+ * @see placeCursorBeforeCharAt
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterCharAt(index: Int): TextEditResult =
+    PlaceCursorResult(this, index, after = true, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the cursor at the end of the text.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAfterLastChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAtEnd(): TextEditResult = PlaceCursorAtEndResult
+
+/**
+ * Returns a [TextEditResult] that places the cursor after the last change made to this
+ * [TextFieldBuffer].
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAtEnd
+ * @see placeCursorBeforeFirstChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorAfterLastChange(): TextEditResult =
+    PlaceCursorAfterLastChangeResult
+
+/**
+ * Returns a [TextEditResult] that places the cursor before the first change made to this
+ * [TextFieldBuffer].
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see placeCursorAfterLastChange
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.placeCursorBeforeFirstChange(): TextEditResult =
+    PlaceCursorBeforeFirstChangeResult
+
+/**
+ * Returns a [TextEditResult] that places the selection around the given [range] in codepoints.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If the start or end of [range] fall inside invalid runs, the values will be adjusted to the
+ * nearest earlier and later codepoints, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the end
+ * of the selection at the end of the field, after the last codepoint, pass index
+ * [TextFieldBuffer.codepointLength]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCodepointAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.codepointLength], inclusive.
+ *
+ * @see selectCharsIn
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectCodepointsIn(range: TextRange): TextEditResult =
+    SelectRangeResult(this, range, inCodepoints = true)
+
+/**
+ * Returns a [TextEditResult] that places the selection around the given [range] in characters.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * If the start or end of [range] fall inside surrogate pairs or other invalid runs, the values will
+ * be adjusted to the nearest earlier and later characters, respectively.
+ *
+ * To place the start of the selection at the beginning of the field, pass index 0. To place the end
+ * of the selection at the end of the field, after the last character, pass index
+ * [TextFieldBuffer.length]. Passing a zero-length range is the same as calling
+ * [placeCursorBeforeCharAt].
+ *
+ * @param range Codepoint range of the selection, should be in range 0 to
+ * [TextFieldBuffer.length], inclusive.
+ *
+ * @see selectCharsIn
+ * @see TextFieldState.edit
+ */
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectCharsIn(range: TextRange): TextEditResult =
+    SelectRangeResult(this, range, inCodepoints = false)
+
+/**
+ * Returns a [TextEditResult] that places the selection before the first change and after the
+ * last change.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see selectAll
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectAllChanges(): TextEditResult = SelectAllChangesResult
+
+/**
+ * Returns a [TextEditResult] that places the selection around all the text.
+ *
+ * _Note: This method has no side effects – just calling it will not perform the action, its return
+ * value must be returned from [TextFieldState.edit]._
+ *
+ * @see selectAllChanges
+ * @see TextFieldState.edit
+ */
+@Suppress("UnusedReceiverParameter")
+@ExperimentalFoundationApi
+fun TextFieldBuffer.selectAll(): TextEditResult = SelectAllResult
+
+private object PlaceCursorAtEndResult : TextEditResult() {
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange = TextRange(newValue.length)
+
+    override fun toString(): String = "placeCursorAtEnd()"
+}
+
+private object PlaceCursorAfterLastChangeResult : TextEditResult() {
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange {
+        return if (newValue.changes.changeCount == 0) {
+            oldValue.selectionInChars
+        } else {
+            TextRange(newValue.changes.getRange(newValue.changes.changeCount).max)
+        }
+    }
+
+    override fun toString(): String = "placeCursorAfterLastChange()"
+}
+
+private object PlaceCursorBeforeFirstChangeResult : TextEditResult() {
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange {
+        return if (newValue.changes.changeCount == 0) {
+            oldValue.selectionInChars
+        } else {
+            TextRange(newValue.changes.getRange(0).min)
+        }
+    }
+
+    override fun toString(): String = "placeCursorBeforeFirstChange()"
+}
+
+private object SelectAllChangesResult : TextEditResult() {
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange {
+        val changes = newValue.changes
+        return if (changes.changeCount == 0) {
+            oldValue.selectionInChars
+        } else {
+            TextRange(
+                changes.getRange(0).min,
+                changes.getRange(changes.changeCount).max
+            )
+        }
+    }
+
+    override fun toString(): String = "selectAllChanges()"
+}
+
+private object SelectAllResult : TextEditResult() {
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange = TextRange(0, newValue.length)
+
+    override fun toString(): String = "selectAll()"
+}
+
+private class PlaceCursorResult(
+    value: TextFieldBuffer,
+    private val rawIndex: Int,
+    private val after: Boolean,
+    private val inCodepoints: Boolean
+) : TextEditResult() {
+
+    init {
+        value.requireValidIndex(rawIndex, inCodepoints)
+    }
+
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange {
+        var index = if (after) rawIndex + 1 else rawIndex
+        index = index.coerceAtMost(if (inCodepoints) newValue.codepointLength else newValue.length)
+        index = if (inCodepoints) newValue.codepointIndexToCharIndex(index) else index
+        return TextRange(index)
+    }
+
+    override fun toString(): String = buildString {
+        append("placeCursor")
+        append(if (after) "After" else "Before")
+        append(if (inCodepoints) "Codepoint" else "Char")
+        append("At(index=$rawIndex)")
+    }
+}
+
+private class SelectRangeResult(
+    value: TextFieldBuffer,
+    private val rawRange: TextRange,
+    private val inCodepoints: Boolean
+) : TextEditResult() {
+
+    init {
+        value.requireValidRange(rawRange, inCodepoints)
+    }
+
+    override fun calculateSelection(
+        oldValue: TextFieldCharSequence,
+        newValue: TextFieldBuffer
+    ): TextRange = if (inCodepoints) newValue.codepointsToChars(rawRange) else rawRange
+
+    override fun toString(): String = buildString {
+        append("select")
+        append(if (inCodepoints) "Codepoints" else "Chars")
+        append("In(range=$rawRange)")
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValue.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
similarity index 75%
rename from compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValue.kt
rename to compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
index fe612cb..267535c 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValue.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBuffer.kt
@@ -18,27 +18,30 @@
 
 import androidx.annotation.CallSuper
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
 import androidx.compose.foundation.text2.input.internal.ChangeTracker
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 
 /**
- * A mutable version of [TextFieldValue], similar to [StringBuilder].
+ * A text buffer that can be edited, similar to [StringBuilder].
  *
- * This class provides methods for changing the text, such as [replace] and [append].
+ * This class provides methods for changing the text, such as [replace], [append], [insert], and
+ * [delete].
  *
- * To get one of these, and for usage samples, see [TextFieldState.edit]. Every change to the buffer is tracked in a [ChangeList] which you can access via the
- * [changes] property.
+ * To get one of these, and for usage samples, see [TextFieldState.edit]. Every change to the buffer
+ * is tracked in a [ChangeList] which you can access via the [changes] property.
+ *
+ * [TextFieldBufferWithSelection] is a special type of buffer that has an associated cursor position
+ * or selection range.
  */
 @ExperimentalFoundationApi
-open class MutableTextFieldValue internal constructor(
-    internal val value: TextFieldValue,
+open class TextFieldBuffer internal constructor(
+    internal val value: TextFieldCharSequence,
     initialChanges: ChangeTracker? = null
 ) : CharSequence,
     Appendable {
 
-    private val buffer = StringBuffer(value.text)
+    private val buffer = StringBuffer(value)
 
     /**
      * Lazily-allocated [ChangeTracker], initialized on the first text change.
@@ -58,9 +61,9 @@
     val codepointLength: Int get() = buffer.codePointCount(0, length)
 
     /**
-     * The [ChangeList] that represents the changes made to this value. The returned [ChangeList]
-     * will always represent the total list of changes made to this value, including changes made
-     * after this property is read.
+     * The [ChangeList] represents the changes made to this value and is inherently mutable. This
+     * means that the returned [ChangeList] always reflects the complete list of changes made to
+     * this value at any given time, even those made after reading this property.
      *
      * @sample androidx.compose.foundation.samples.BasicTextField2ChangeIterationSample
      * @sample androidx.compose.foundation.samples.BasicTextField2ChangeReverseIterationSample
@@ -71,18 +74,21 @@
      * Replaces the text between [start] (inclusive) and [end] (exclusive) in this value with
      * [text], and records the change in [changes].
      *
+     * @param start The character offset of the first character to replace.
+     * @param end The character offset of the first character after the text to replace.
+     * @param text The text to replace the range `[start, end)` with.
+     *
+     * @see append
      * @see insert
+     * @see delete
      */
     fun replace(start: Int, end: Int, text: String) {
         onTextWillChange(TextRange(start, end), text.length)
         buffer.replace(start, end, text)
     }
 
-    override fun append(char: Char): Appendable = apply {
-        onTextWillChange(TextRange(length), 1)
-        buffer.append(char)
-    }
-
+    // Doc inherited from Appendable.
+    // This append overload should be first so it ends up being the target of links to this method.
     override fun append(text: CharSequence?): Appendable = apply {
         if (text != null) {
             onTextWillChange(TextRange(length), text.length)
@@ -90,6 +96,7 @@
         }
     }
 
+    // Doc inherited from Appendable.
     override fun append(text: CharSequence?, start: Int, end: Int): Appendable = apply {
         if (text != null) {
             onTextWillChange(TextRange(length), end - start)
@@ -97,6 +104,12 @@
         }
     }
 
+    // Doc inherited from Appendable.
+    override fun append(char: Char): Appendable = apply {
+        onTextWillChange(TextRange(length), 1)
+        buffer.append(char)
+    }
+
     /**
      * Called just before the text contents are about to change.
      *
@@ -116,10 +129,14 @@
 
     override fun toString(): String = buffer.toString()
 
-    internal fun toTextFieldValue(
+    internal fun clearChangeList() {
+        changeTracker?.clearChanges()
+    }
+
+    internal fun toTextFieldCharSequence(
         selection: TextRange,
         composition: TextRange? = null
-    ): TextFieldValue = TextFieldValue(
+    ): TextFieldCharSequence = TextFieldCharSequence(
         buffer.toString(),
         selection = selection,
         composition = composition
@@ -147,8 +164,8 @@
         }
     }
 
-    internal fun toTextFieldValue(selection: TextRange): TextFieldValue =
-        TextFieldValue(buffer.toString(), selection = selection)
+    internal fun toTextFieldCharSequence(selection: TextRange): TextFieldCharSequence =
+        TextFieldCharSequence(buffer.toString(), selection = selection)
 
     internal fun codepointsToChars(range: TextRange): TextRange = TextRange(
         codepointIndexToCharIndex(range.start),
@@ -166,7 +183,7 @@
 
     /**
      * The ordered list of non-overlapping and discontinuous changes performed on a
-     * [MutableTextFieldValue] during the current [edit][TextFieldState.edit] or
+     * [TextFieldBuffer] during the current [edit][TextFieldState.edit] or
      * [filter][TextEditFilter.filter] operation. Changes are listed in the order they appear in the
      * text, not the order in which they were made. Overlapping changes are represented as a single
      * change.
@@ -179,7 +196,7 @@
         val changeCount: Int
 
         /**
-         * Returns the range in the [MutableTextFieldValue] that was changed.
+         * Returns the range in the [TextFieldBuffer] that was changed.
          *
          * @throws IndexOutOfBoundsException If [changeIndex] is not in [0, [changeCount]).
          */
@@ -195,20 +212,36 @@
 }
 
 /**
- * Insert [text] at the given [index] in this value.
+ * Insert [text] at the given [index] in this value. Pass 0 to insert [text] at the beginning of
+ * this buffer, and pass [TextFieldBuffer.length] to insert [text] at the end of this buffer.
  *
- * @see MutableTextFieldValue.replace
+ * This is equivalent to calling `replace(index, index, text)`.
+ *
+ * @param index The character offset at which to insert [text].
+ * @param text The text to insert.
+ *
+ * @see TextFieldBuffer.replace
+ * @see TextFieldBuffer.append
+ * @see TextFieldBuffer.delete
  */
 @ExperimentalFoundationApi
-fun MutableTextFieldValue.insert(index: Int, text: String) {
+fun TextFieldBuffer.insert(index: Int, text: String) {
     replace(index, index, text)
 }
 
 /**
- * Delete the text between [start] (inclusive) and [end] (exclusive).
+ * Delete the text between [start] (inclusive) and [end] (exclusive). Pass 0 as [start] and
+ * [TextFieldBuffer.length] as [end] to delete everything in this buffer.
+ *
+ * @param start The character offset of the first character to delete.
+ * @param end The character offset of the first character after the deleted range.
+ *
+ * @see TextFieldBuffer.replace
+ * @see TextFieldBuffer.append
+ * @see TextFieldBuffer.insert
  */
 @ExperimentalFoundationApi
-fun MutableTextFieldValue.delete(start: Int, end: Int) {
+fun TextFieldBuffer.delete(start: Int, end: Int) {
     replace(start, end, "")
 }
 
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt
similarity index 64%
rename from compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelection.kt
rename to compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt
index 8b9c20b..56c698e 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelection.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelection.kt
@@ -19,21 +19,24 @@
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.internal.ChangeTracker
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 
 /**
- * A [MutableTextFieldValue] that also provides both read and write access to the current selection
+ * A [TextFieldBuffer] that also provides both read and write access to the current selection,
  * used by [TextEditFilter.filter].
  */
 @ExperimentalFoundationApi
-class MutableTextFieldValueWithSelection internal constructor(
-    value: TextFieldValue,
+class TextFieldBufferWithSelection internal constructor(
+    value: TextFieldCharSequence,
+    /** The value reverted to when [revertAllChanges] is called. */
+    private val sourceValue: TextFieldCharSequence = TextFieldCharSequence(),
     initialChanges: ChangeTracker? = null
-) : MutableTextFieldValue(value, initialChanges) {
+) : TextFieldBuffer(value, initialChanges) {
 
     /**
      * True if the selection range has non-zero length. If this is false, then the selection
      * represents the cursor.
+     *
+     * @see selectionInChars
      */
     val hasSelection: Boolean
         get() = !selectionInChars.collapsed
@@ -43,7 +46,7 @@
      *
      * @see selectionInCodepoints
      */
-    var selectionInChars: TextRange = value.selection
+    var selectionInChars: TextRange = value.selectionInChars
         private set
 
     /**
@@ -61,12 +64,13 @@
      *
      * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the
      * end of the field, after the last character, pass index
-     * [MutableTextFieldValue.codepointLength].
+     * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
      *
      * @param index Codepoint index to place cursor before, should be in range 0 to
-     * [MutableTextFieldValue.codepointLength], inclusive.
+     * [TextFieldBuffer.codepointLength], inclusive.
      *
      * @see placeCursorBeforeCharAt
+     * @see placeCursorAfterCodepointAt
      */
     fun placeCursorBeforeCodepointAt(index: Int) {
         requireValidIndex(index, inCodepoints = true)
@@ -80,13 +84,15 @@
      * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
      * nearest earlier index.
      *
-     * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
-     * of the field, after the last character, pass index [MutableTextFieldValue.length].
+     * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the
+     * end of the field, after the last character, pass index [TextFieldBuffer.length] or call
+     * [placeCursorAtEnd].
      *
-     * @param index Codepoint index to place cursor before, should be in range 0 to
-     * [MutableTextFieldValue.length], inclusive.
+     * @param index Character index to place cursor before, should be in range 0 to
+     * [TextFieldBuffer.length], inclusive.
      *
      * @see placeCursorBeforeCodepointAt
+     * @see placeCursorAfterCharAt
      */
     fun placeCursorBeforeCharAt(index: Int) {
         requireValidIndex(index, inCodepoints = false)
@@ -94,15 +100,57 @@
     }
 
     /**
+     * Places the cursor after the codepoint at the given index.
+     *
+     * If [index] is inside an invalid run, the cursor will be placed at the nearest later index.
+     *
+     * To place the cursor at the end of the field, after the last character, pass index
+     * [TextFieldBuffer.codepointLength] or call [placeCursorAtEnd].
+     *
+     * @param index Codepoint index to place cursor after, should be in range 0 (inclusive) to
+     * [TextFieldBuffer.codepointLength] (exclusive).
+     *
+     * @see placeCursorAfterCharAt
+     * @see placeCursorBeforeCodepointAt
+     */
+    fun placeCursorAfterCodepointAt(index: Int) {
+        requireValidIndex(index, inCodepoints = true)
+        val charIndex = codepointIndexToCharIndex((index + 1).coerceAtMost(codepointLength))
+        selectionInChars = TextRange(charIndex)
+    }
+
+    /**
+     * Places the cursor after the character at the given index.
+     *
+     * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
+     * nearest later index.
+     *
+     * To place the cursor at the end of the field, after the last character, pass index
+     * [TextFieldBuffer.length] or call [placeCursorAtEnd].
+     *
+     * @param index Character index to place cursor after, should be in range 0 (inclusive) to
+     * [TextFieldBuffer.length] (exclusive).
+     *
+     * @see placeCursorAfterCodepointAt
+     * @see placeCursorBeforeCharAt
+     */
+    fun placeCursorAfterCharAt(index: Int) {
+        requireValidIndex(index, inCodepoints = false)
+        selectionInChars = TextRange((index + 1).coerceAtMost(length))
+    }
+
+    /**
      * Places the cursor at the end of the text.
+     *
+     * @see placeCursorBeforeFirstChange
+     * @see placeCursorAfterLastChange
      */
     fun placeCursorAtEnd() {
         selectionInChars = TextRange(length)
     }
 
     /**
-     * Returns a [TextFieldEditResult] that places the cursor after the last change made to this
-     * [MutableTextFieldValue].
+     * Places the cursor after the last change made to this [TextFieldBufferWithSelection].
      *
      * @see placeCursorAtEnd
      * @see placeCursorBeforeFirstChange
@@ -114,8 +162,7 @@
     }
 
     /**
-     * Returns a [TextFieldEditResult] that places the cursor before the first change made to this
-     * [MutableTextFieldValue].
+     * Places the cursor before the first change made to this [TextFieldBufferWithSelection].
      *
      * @see placeCursorAfterLastChange
      */
@@ -133,11 +180,11 @@
      *
      * To place the start of the selection at the beginning of the field, pass index 0. To place the
      * end of the selection at the end of the field, after the last codepoint, pass index
-     * [MutableTextFieldValue.codepointLength]. Passing a zero-length range is the same as calling
+     * [TextFieldBuffer.codepointLength]. Passing a zero-length range is the same as calling
      * [placeCursorBeforeCodepointAt].
      *
      * @param range Codepoint range of the selection, should be in range 0 to
-     * [MutableTextFieldValue.codepointLength], inclusive.
+     * [TextFieldBuffer.codepointLength], inclusive.
      *
      * @see selectCharsIn
      */
@@ -154,13 +201,13 @@
      *
      * To place the start of the selection at the beginning of the field, pass index 0. To place the end
      * of the selection at the end of the field, after the last character, pass index
-     * [MutableTextFieldValue.length]. Passing a zero-length range is the same as calling
+     * [TextFieldBuffer.length]. Passing a zero-length range is the same as calling
      * [placeCursorBeforeCharAt].
      *
      * @param range Codepoint range of the selection, should be in range 0 to
-     * [MutableTextFieldValue.length], inclusive.
+     * [TextFieldBuffer.length], inclusive.
      *
-     * @see selectCharsIn
+     * @see selectCodepointsIn
      */
     fun selectCharsIn(range: TextRange) {
         requireValidRange(range, inCodepoints = false)
@@ -169,14 +216,15 @@
 
     /**
      * Places the selection around all the text.
+     *
+     * @see selectAllChanges
      */
     fun selectAll() {
         selectionInChars = TextRange(0, length)
     }
 
     /**
-     * Returns a [TextFieldEditResult] that places the selection before the first change and after the
-     * last change.
+     * Places the selection before the first change and after the last change.
      *
      * @see selectAll
      */
@@ -192,11 +240,15 @@
     }
 
     /**
-     * Resets this value to [value].
+     * Revert all changes made to this value since it was created.
+     *
+     * After calling this method, this object will be in the same state it was when it was initially
+     * created, and [changes] will be empty.
      */
-    fun resetTo(value: TextFieldValue) {
-        replace(0, length, value.text)
-        selectionInChars = value.selection
+    fun revertAllChanges() {
+        replace(0, length, sourceValue.toString())
+        selectionInChars = sourceValue.selectionInChars
+        clearChangeList()
     }
 
     override fun onTextWillChange(rangeToBeReplaced: TextRange, newLength: Int) {
@@ -242,6 +294,6 @@
         selectionInChars = TextRange(selStart, selEnd)
     }
 
-    internal fun toTextFieldValue(composition: TextRange? = null): TextFieldValue =
-        toTextFieldValue(selection = selectionInChars, composition = composition)
+    internal fun toTextFieldCharSequence(composition: TextRange? = null): TextFieldCharSequence =
+        toTextFieldCharSequence(selection = selectionInChars, composition = composition)
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt
new file mode 100644
index 0000000..b32f5fa
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequence.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.constrain
+
+/**
+ * An immutable snapshot of the contents of a [TextFieldState].
+ *
+ * This class is a [CharSequence] and directly represents the text being edited. It also stores
+ * the current [selectionInChars] of the field, which may either represent the cursor (if the
+ * selection is [collapsed][TextRange.collapsed]) or the selection range.
+ *
+ * This class also may contain the range being composed by the IME, if any, although this is not
+ * exposed.
+ *
+ * @see TextFieldBuffer
+ */
+@ExperimentalFoundationApi
+sealed interface TextFieldCharSequence : CharSequence {
+    /**
+     * The selection range. If the selection is collapsed, it represents cursor
+     * location. When selection range is out of bounds, it is constrained with the text length.
+     */
+    val selectionInChars: TextRange
+
+    /**
+     * Composition range created by IME. If null, there is no composition range.
+     *
+     * Input service composition is an instance of text produced by IME. An example visual for the
+     * composition is that the currently composed word is visually separated from others with
+     * underline, or text background. For description of composition please check
+     * [W3C IME Composition](https://www.w3.org/TR/ime-api/#ime-composition)
+     *
+     * Composition can only be set by the system.
+     */
+    val compositionInChars: TextRange?
+
+    /**
+     * Returns true if the text in this object is equal to the text in [other], disregarding any
+     * other properties of this (such as selection) or [other].
+     */
+    fun contentEquals(other: CharSequence): Boolean
+
+    abstract override fun toString(): String
+    abstract override fun equals(other: Any?): Boolean
+    abstract override fun hashCode(): Int
+}
+
+@ExperimentalFoundationApi
+fun TextFieldCharSequence(
+    text: String = "",
+    selection: TextRange = TextRange.Zero
+): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition = null)
+
+@OptIn(ExperimentalFoundationApi::class)
+internal fun TextFieldCharSequence(
+    text: CharSequence,
+    selection: TextRange,
+    composition: TextRange? = null
+): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition)
+
+@OptIn(ExperimentalFoundationApi::class)
+private class TextFieldCharSequenceWrapper(
+    private val text: CharSequence,
+    selection: TextRange,
+    composition: TextRange?
+) : TextFieldCharSequence {
+
+    override val length: Int
+        get() = text.length
+
+    override val selectionInChars: TextRange = selection.constrain(0, text.length)
+
+    override val compositionInChars: TextRange? = composition?.constrain(0, text.length)
+
+    override operator fun get(index: Int): Char = text[index]
+
+    override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
+        text.subSequence(startIndex, endIndex)
+
+    override fun toString(): String = text.toString()
+
+    override fun contentEquals(other: CharSequence): Boolean = text.contentEquals(other)
+
+    /**
+     * Returns true if [other] is a [TextFieldCharSequence] with the same contents, text, and composition.
+     * To compare just the text, call [contentEquals].
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as TextFieldCharSequenceWrapper
+
+        if (selectionInChars != other.selectionInChars) return false
+        if (compositionInChars != other.compositionInChars) return false
+        if (!contentEquals(other.text)) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = text.hashCode()
+        result = 31 * result + selectionInChars.hashCode()
+        result = 31 * result + (compositionInChars?.hashCode() ?: 0)
+        return result
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldEditResult.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldEditResult.kt
deleted file mode 100644
index 616487b0..0000000
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldEditResult.kt
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:OptIn(ExperimentalFoundationApi::class)
-
-package androidx.compose.foundation.text2.input
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
-
-/**
- * A value to be returned from [TextFieldState.edit] that specifies where the place the cursor or
- * selection.
- *
- * Predefined results include:
- *  - [MutableTextFieldValue.placeCursorAtEnd]
- *  - [MutableTextFieldValue.placeCursorBeforeFirstChange]
- *  - [MutableTextFieldValue.placeCursorAfterLastChange]
- *  - [MutableTextFieldValue.placeCursorBeforeCharAt]
- *  - [MutableTextFieldValue.placeCursorBeforeCodepointAt]
- *  - [MutableTextFieldValue.selectAll]
- *  - [MutableTextFieldValue.selectAllChanges]
- *  - [MutableTextFieldValue.selectCharsIn]
- *  - [MutableTextFieldValue.selectCodepointsIn]
- */
-@ExperimentalFoundationApi
-sealed class TextFieldEditResult {
-    /**
-     * Returns the [TextRange] to set as the new selection. If the selection is collapsed, it will
-     * set the cursor instead.
-     */
-    internal abstract fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange
-}
-
-/**
- * Returns a [TextFieldEditResult] that places the cursor before the codepoint at the given index.
- *
- * If [index] is inside an invalid run, the cursor will be placed at the nearest earlier index.
- *
- * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
- * of the field, after the last character, pass index [MutableTextFieldValue.codepointLength].
- *
- * @param index Codepoint index to place cursor before, should be in range 0 to
- * [MutableTextFieldValue.codepointLength], inclusive.
- *
- * @see placeCursorBeforeCharAt
- * @see TextFieldState.edit
- */
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.placeCursorBeforeCodepointAt(index: Int): TextFieldEditResult =
-    object : SelectRangeResult(this, TextRange(index), inCodepoints = true) {
-        override fun toString(): String = "placeCursorBeforeCodepoint(index=$index)"
-    }
-
-/**
- * Returns a [TextFieldEditResult] that places the cursor before the character at the given index.
- *
- * If [index] is inside a surrogate pair or other invalid run, the cursor will be placed at the
- * nearest earlier index.
- *
- * To place the cursor at the beginning of the field, pass index 0. To place the cursor at the end
- * of the field, after the last character, pass index [MutableTextFieldValue.length].
- *
- * @param index Codepoint index to place cursor before, should be in range 0 to
- * [MutableTextFieldValue.length], inclusive.
- *
- * @see placeCursorBeforeCodepointAt
- * @see TextFieldState.edit
- */
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.placeCursorBeforeCharAt(index: Int): TextFieldEditResult =
-    object : SelectRangeResult(this, TextRange(index), inCodepoints = false) {
-        override fun toString(): String = "placeCursorBeforeChar(index=$index)"
-    }
-
-/**
- * Returns a [TextFieldEditResult] that places the cursor at the end of the text.
- *
- * @see placeCursorAfterLastChange
- * @see TextFieldState.edit
- */
-@Suppress("UnusedReceiverParameter")
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.placeCursorAtEnd(): TextFieldEditResult = PlaceCursorAtEndResult
-
-/**
- * Returns a [TextFieldEditResult] that places the cursor after the last change made to this
- * [MutableTextFieldValue].
- *
- * @see placeCursorAtEnd
- * @see placeCursorBeforeFirstChange
- * @see TextFieldState.edit
- */
-@Suppress("UnusedReceiverParameter")
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.placeCursorAfterLastChange(): TextFieldEditResult =
-    PlaceCursorAfterLastChangeResult
-
-/**
- * Returns a [TextFieldEditResult] that places the cursor before the first change made to this
- * [MutableTextFieldValue].
- *
- * @see placeCursorAfterLastChange
- * @see TextFieldState.edit
- */
-@Suppress("UnusedReceiverParameter")
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.placeCursorBeforeFirstChange(): TextFieldEditResult =
-    PlaceCursorBeforeFirstChangeResult
-
-/**
- * Returns a [TextFieldEditResult] that places the selection around the given [range] in codepoints.
- *
- * If the start or end of [range] fall inside invalid runs, the values will be adjusted to the
- * nearest earlier and later codepoints, respectively.
- *
- * To place the start of the selection at the beginning of the field, pass index 0. To place the end
- * of the selection at the end of the field, after the last codepoint, pass index
- * [MutableTextFieldValue.codepointLength]. Passing a zero-length range is the same as calling
- * [placeCursorBeforeCodepointAt].
- *
- * @param range Codepoint range of the selection, should be in range 0 to
- * [MutableTextFieldValue.codepointLength], inclusive.
- *
- * @see selectCharsIn
- * @see TextFieldState.edit
- */
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.selectCodepointsIn(range: TextRange): TextFieldEditResult =
-    object : SelectRangeResult(this, range, inCodepoints = true) {
-        override fun toString(): String = "selectCodepoints(range=$range)"
-    }
-
-/**
- * Returns a [TextFieldEditResult] that places the selection around the given [range] in characters.
- *
- * If the start or end of [range] fall inside surrogate pairs or other invalid runs, the values will
- * be adjusted to the nearest earlier and later characters, respectively.
- *
- * To place the start of the selection at the beginning of the field, pass index 0. To place the end
- * of the selection at the end of the field, after the last character, pass index
- * [MutableTextFieldValue.length]. Passing a zero-length range is the same as calling
- * [placeCursorBeforeCharAt].
- *
- * @param range Codepoint range of the selection, should be in range 0 to
- * [MutableTextFieldValue.length], inclusive.
- *
- * @see selectCharsIn
- * @see TextFieldState.edit
- */
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.selectCharsIn(range: TextRange): TextFieldEditResult =
-    object : SelectRangeResult(this, range, inCodepoints = false) {
-        override fun toString(): String = "selectChars(range=$range)"
-    }
-
-/**
- * Returns a [TextFieldEditResult] that places the selection before the first change and after the
- * last change.
- *
- * @see selectAll
- * @see TextFieldState.edit
- */
-@Suppress("UnusedReceiverParameter")
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.selectAllChanges(): TextFieldEditResult = SelectAllChangesResult
-
-/**
- * Returns a [TextFieldEditResult] that places the selection around all the text.
- *
- * @see selectAllChanges
- * @see TextFieldState.edit
- */
-@Suppress("UnusedReceiverParameter")
-@ExperimentalFoundationApi
-fun MutableTextFieldValue.selectAll(): TextFieldEditResult = SelectAllResult
-
-private object PlaceCursorAtEndResult : TextFieldEditResult() {
-    override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange = TextRange(newValue.length)
-
-    override fun toString(): String = "placeCursorAtEnd()"
-}
-
-private object PlaceCursorAfterLastChangeResult : TextFieldEditResult() {
-    override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange {
-        return if (newValue.changes.changeCount == 0) {
-            oldValue.selection
-        } else {
-            TextRange(newValue.changes.getRange(newValue.changes.changeCount).max)
-        }
-    }
-
-    override fun toString(): String = "placeCursorAfterLastChange()"
-}
-
-private object PlaceCursorBeforeFirstChangeResult : TextFieldEditResult() {
-    override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange {
-        return if (newValue.changes.changeCount == 0) {
-            oldValue.selection
-        } else {
-            TextRange(newValue.changes.getRange(0).min)
-        }
-    }
-
-    override fun toString(): String = "placeCursorBeforeFirstChange()"
-}
-
-private object SelectAllChangesResult : TextFieldEditResult() {
-    override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange {
-        val changes = newValue.changes
-        return if (changes.changeCount == 0) {
-            oldValue.selection
-        } else {
-            TextRange(
-                changes.getRange(0).min,
-                changes.getRange(changes.changeCount).max
-            )
-        }
-    }
-
-    override fun toString(): String = "selectAllChanges()"
-}
-
-private object SelectAllResult : TextFieldEditResult() {
-    override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange = TextRange(0, newValue.length)
-
-    override fun toString(): String = "selectAll()"
-}
-
-/** Open for [toString] overrides. */
-private open class SelectRangeResult(
-    value: MutableTextFieldValue,
-    private val rawRange: TextRange,
-    private val inCodepoints: Boolean
-) : TextFieldEditResult() {
-
-    init {
-        value.requireValidRange(rawRange, inCodepoints)
-    }
-
-    final override fun calculateSelection(
-        oldValue: TextFieldValue,
-        newValue: MutableTextFieldValue
-    ): TextRange = if (inCodepoints) newValue.codepointsToChars(rawRange) else rawRange
-}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.kt
new file mode 100644
index 0000000..e2e151f
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldLineLimits.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
+import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+
+/**
+ * Values that specify the text wrapping, scrolling, and height measurement behavior for
+ * text fields.
+ *
+ * @see SingleLine
+ * @see MultiLine
+ */
+@ExperimentalFoundationApi
+@Stable
+sealed interface TextFieldLineLimits {
+
+    /**
+     * The text field is always a single line tall, ignores newlines in the text, and scrolls
+     * horizontally when the text overflows.
+     */
+    object SingleLine : TextFieldLineLimits
+
+    /**
+     * The text field will be at least [minHeightInLines] tall, if the text overflows it will wrap,
+     * and if the text ends up being more than one line the field will grow until it is
+     * [maxHeightInLines] tall and then start scrolling vertically.
+     *
+     * It is required that 1 ≤ [minHeightInLines] ≤ [maxHeightInLines].
+     */
+    @Immutable
+    class MultiLine(
+        val minHeightInLines: Int = 1,
+        val maxHeightInLines: Int = Int.MAX_VALUE
+    ) : TextFieldLineLimits {
+        init {
+            require(minHeightInLines in 1..maxHeightInLines) {
+                "Expected 1 ≤ minHeightInLines ≤ maxHeightInLines, were " +
+                    "$minHeightInLines, $maxHeightInLines"
+            }
+        }
+
+        override fun toString(): String =
+            "MultiLine(minHeightInLines=$minHeightInLines, maxHeightInLines=$maxHeightInLines)"
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (javaClass != other?.javaClass) return false
+            other as MultiLine
+            if (minHeightInLines != other.minHeightInLines) return false
+            if (maxHeightInLines != other.maxHeightInLines) return false
+            return true
+        }
+
+        override fun hashCode(): Int {
+            var result = minHeightInLines
+            result = 31 * result + maxHeightInLines
+            return result
+        }
+    }
+
+    companion object {
+        val Default: TextFieldLineLimits = MultiLine()
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt
index f4f22e0..6173da3 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextFieldState.kt
@@ -21,54 +21,88 @@
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.internal.EditProcessor
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
 import androidx.compose.runtime.saveable.SaverScope
 import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collectLatest
 
 /**
- * The editable text state of a text field, including both the text itself and position of the
+ * The editable text state of a text field, including both the [text] itself and position of the
  * cursor or selection.
  *
- * To change the state, call [edit].
+ * To change the text field contents programmatically, call [edit], [setTextAndSelectAll], or
+ * [setTextAndPlaceCursorAtEnd]. To observe the value of the field over time, call
+ * [forEachTextValue] or [textAsFlow].
+ *
+ * When instantiating this class from a composable, use [rememberTextFieldState] to automatically
+ * save and restore the field state. For more advanced use cases, pass [TextFieldState.Saver] to
+ * [rememberSaveable].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2StateCompleteSample
  */
 @ExperimentalFoundationApi
-class TextFieldState(initialValue: TextFieldValue = TextFieldValue()) {
+@Stable
+class TextFieldState(
+    initialText: String = "",
+    initialSelectionInChars: TextRange = TextRange.Zero
+) {
+    internal var editProcessor =
+        EditProcessor(TextFieldCharSequence(initialText, initialSelectionInChars))
 
-    internal var editProcessor = EditProcessor(initialValue)
-
-    val value: TextFieldValue
+    /**
+     * The current text and selection. This value will automatically update when the user enters
+     * text or otherwise changes the text field contents. To change it programmatically, call
+     * [edit].
+     *
+     * This is backed by snapshot state, so reading this property in a restartable function (e.g.
+     * a composable function) will cause the function to restart when the text field's value
+     * changes.
+     *
+     * To observe changes to this property outside a restartable function, see [forEachTextValue]
+     * and [textAsFlow].
+     *
+     * @sample androidx.compose.foundation.samples.BasicTextField2TextDerivedStateSample
+     *
+     * @see edit
+     * @see forEachTextValue
+     * @see textAsFlow
+     */
+    val text: TextFieldCharSequence
         get() = editProcessor.value
 
     /**
      * Runs [block] with a mutable version of the current state. The block can make changes to the
      * text, and must specify the new location of the cursor or selection by returning a
-     * [TextFieldEditResult] such as [placeCursorAtEnd] or [selectAll] (see the documentation on
-     * [TextFieldEditResult] for the full list of prebuilt results).
+     * [TextEditResult] such as [placeCursorAtEnd] or [selectAll] (see the documentation on
+     * [TextEditResult] for the full list of prebuilt results).
      *
      * @sample androidx.compose.foundation.samples.BasicTextField2StateEditSample
+     *
      * @see setTextAndPlaceCursorAtEnd
      * @see setTextAndSelectAll
      */
-    inline fun edit(block: MutableTextFieldValue.() -> TextFieldEditResult) {
-        val mutableValue = startEdit(value)
+    inline fun edit(block: TextFieldBuffer.() -> TextEditResult) {
+        val mutableValue = startEdit(text)
         val result = mutableValue.block()
         commitEdit(mutableValue, result)
     }
 
     override fun toString(): String =
-        "TextFieldState(selection=${value.selection}, text=\"${value.text}\")"
+        "TextFieldState(selectionInChars=${text.selectionInChars}, text=\"$text\")"
 
     @Suppress("ShowingMemberInHiddenClass")
     @PublishedApi
-    internal fun startEdit(value: TextFieldValue): MutableTextFieldValue =
-        MutableTextFieldValue(value)
+    internal fun startEdit(value: TextFieldCharSequence): TextFieldBuffer =
+        TextFieldBuffer(value)
 
     @Suppress("ShowingMemberInHiddenClass")
     @PublishedApi
-    internal fun commitEdit(newValue: MutableTextFieldValue, result: TextFieldEditResult) {
-        val newSelection = result.calculateSelection(value, newValue)
-        val finalValue = newValue.toTextFieldValue(newSelection)
+    internal fun commitEdit(newValue: TextFieldBuffer, result: TextEditResult) {
+        val newSelection = result.calculateSelection(text, newValue)
+        val finalValue = newValue.toTextFieldCharSequence(newSelection)
         editProcessor.reset(finalValue)
     }
 
@@ -81,20 +115,18 @@
     @Suppress("RedundantNullableReturnType")
     object Saver : androidx.compose.runtime.saveable.Saver<TextFieldState, Any> {
         override fun SaverScope.save(value: TextFieldState): Any? = listOf(
-            value.value.text,
-            value.value.selection.start,
-            value.value.selection.end
+            value.text.toString(),
+            value.text.selectionInChars.start,
+            value.text.selectionInChars.end
         )
 
         override fun restore(value: Any): TextFieldState? {
             val (text, selectionStart, selectionEnd) = value as List<*>
             return TextFieldState(
-                TextFieldValue(
-                    text = text as String,
-                    selection = TextRange(
-                        start = selectionStart as Int,
-                        end = selectionEnd as Int
-                    )
+                initialText = text as String,
+                initialSelectionInChars = TextRange(
+                    start = selectionStart as Int,
+                    end = selectionEnd as Int
                 )
             )
         }
@@ -102,6 +134,15 @@
 }
 
 /**
+ * Returns a [Flow] of the values of [TextFieldState.text] as seen from the global snapshot.
+ * The initial value is emitted immediately when the flow is collected.
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2TextValuesSample
+ */
+@ExperimentalFoundationApi
+fun TextFieldState.textAsFlow(): Flow<TextFieldCharSequence> = snapshotFlow { text }
+
+/**
  * Create and remember a [TextFieldState]. The state is remembered using [rememberSaveable] and so
  * will be saved and restored with the composition.
  *
@@ -119,7 +160,17 @@
  * Sets the text in this [TextFieldState] to [text], replacing any text that was previously there,
  * and places the cursor at the end of the new text.
  *
- * To perform more complicated edits on the text, call [TextFieldState.edit].
+ * To perform more complicated edits on the text, call [TextFieldState.edit]. This function is
+ * equivalent to calling:
+ * ```
+ * edit {
+ *   replace(0, length, text)
+ *   placeCursorAtEnd()
+ * }
+ * ```
+ *
+ * @see setTextAndSelectAll
+ * @see TextFieldBuffer.placeCursorAtEnd
  */
 @ExperimentalFoundationApi
 fun TextFieldState.setTextAndPlaceCursorAtEnd(text: String) {
@@ -133,7 +184,17 @@
  * Sets the text in this [TextFieldState] to [text], replacing any text that was previously there,
  * and selects all the text.
  *
- * To perform more complicated edits on the text, call [TextFieldState.edit].
+ * To perform more complicated edits on the text, call [TextFieldState.edit]. This function is
+ * equivalent to calling:
+ * ```
+ * edit {
+ *   replace(0, length, text)
+ *   selectAll()
+ * }
+ * ```
+ *
+ * @see setTextAndPlaceCursorAtEnd
+ * @see TextFieldBuffer.selectAll
  */
 @ExperimentalFoundationApi
 fun TextFieldState.setTextAndSelectAll(text: String) {
@@ -143,9 +204,32 @@
     }
 }
 
+/**
+ * Invokes [block] with the value of [TextFieldState.text], and every time the value is changed.
+ *
+ * The caller will be suspended until its coroutine is cancelled. If the text is changed while
+ * [block] is suspended, [block] will be cancelled and re-executed with the new value immediately.
+ * [block] will never be executed concurrently with itself.
+ *
+ * To get access to a [Flow] of [TextFieldState.text] over time, use [textAsFlow].
+ *
+ * @sample androidx.compose.foundation.samples.BasicTextField2ForEachTextValueSample
+ *
+ * @see textAsFlow
+ */
+@ExperimentalFoundationApi
+suspend fun TextFieldState.forEachTextValue(
+    block: suspend (TextFieldCharSequence) -> Unit
+): Nothing {
+    textAsFlow().collectLatest(block)
+    error("textAsFlow expected not to complete without exception")
+}
+
 @OptIn(ExperimentalFoundationApi::class)
 internal fun TextFieldState.deselect() {
-    if (!value.selection.collapsed) {
-        editProcessor.reset(value.copy(selection = TextRange.Zero, composition = TextRange.Zero))
+    if (!text.selectionInChars.collapsed) {
+        edit {
+            selectCharsIn(TextRange.Zero)
+        }
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt
new file mode 100644
index 0000000..670a51db
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/TextObfuscationMode.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import android.provider.Settings
+import androidx.compose.foundation.ExperimentalFoundationApi
+
+/**
+ * Defines how the text will be obscured in secure text fields.
+ *
+ * Text obscuring refers to replacing the original text content with a mask via various methods.
+ * It is most common in password fields.
+ *
+ * The default behavior for typing input on Desktop has always been to keep it completely hidden.
+ * However, on mobile devices, the default behavior is to briefly reveal the last typed character
+ * for a short period or until another character is typed. This helps the user to follow the text
+ * input while also protecting their privacy by not revealing too much information to others.
+ */
+@ExperimentalFoundationApi
+@JvmInline
+value class TextObfuscationMode internal constructor(val value: Int) {
+    companion object {
+        /**
+         * Do not obscure any content, making all the content visible.
+         *
+         * It can be useful when you want to briefly reveal the content by clicking a reveal button.
+         */
+        val Visible = TextObfuscationMode(0)
+
+        /**
+         * Default behavior on mobile devices. Reveals the last typed character for a short amount
+         * of time.
+         *
+         * Note; this feature also depends on a system setting called
+         * [Settings.System.TEXT_SHOW_PASSWORD]. If the system setting is disabled, this option
+         * behaves exactly as [Hidden].
+         */
+        val RevealLastTyped = TextObfuscationMode(1)
+
+        /**
+         * Default behavior on desktop platforms. All characters are hidden.
+         */
+        val Hidden = TextObfuscationMode(2)
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt
index 4a3d06c..1877cfa 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/AndroidTextInputAdapter.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalFoundationApi::class)
+
 package androidx.compose.foundation.text2.input.internal
 
 import android.os.Looper
@@ -25,8 +27,10 @@
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputConnection
 import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.ui.text.input.ImeAction
@@ -35,15 +39,17 @@
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.input.PlatformTextInput
 import androidx.compose.ui.text.input.PlatformTextInputAdapter
-import androidx.compose.ui.text.input.TextFieldValue
 import androidx.core.view.inputmethod.EditorInfoCompat
 import java.util.concurrent.Executor
 import org.jetbrains.annotations.TestOnly
 
-private const val DEBUG = false
+/**
+ * Enable to print logs during debugging, see [logDebug].
+ */
+@VisibleForTesting
+internal const val TIA_DEBUG = false
 private const val TAG = "AndroidTextInputAdapter"
 
-@OptIn(ExperimentalFoundationApi::class)
 internal class AndroidTextInputAdapter constructor(
     view: View,
     private val platformTextInput: PlatformTextInput
@@ -56,25 +62,25 @@
     private val textInputCommandExecutor = TextInputCommandExecutor(view, inputMethodManager)
 
     private val resetListener = EditProcessor.ResetListener { old, new ->
-        val needUpdateSelection = (old.selection != new.selection) ||
-            old.composition != new.composition
+        val needUpdateSelection = (old.selectionInChars != new.selectionInChars) ||
+            old.compositionInChars != new.compositionInChars
         if (needUpdateSelection) {
             inputMethodManager.updateSelection(
-                selectionStart = new.selection.min,
-                selectionEnd = new.selection.max,
-                compositionStart = new.composition?.min ?: -1,
-                compositionEnd = new.composition?.max ?: -1
+                selectionStart = new.selectionInChars.min,
+                selectionEnd = new.selectionInChars.max,
+                compositionStart = new.compositionInChars?.min ?: -1,
+                compositionEnd = new.compositionInChars?.max ?: -1
             )
         }
 
-        if (old.text != new.text) {
+        if (!old.contentEquals(new)) {
             inputMethodManager.restartInput()
         }
     }
 
     override fun createInputConnection(outAttrs: EditorInfo): InputConnection {
         logDebug { "createInputConnection" }
-        val value = currentTextInputSession?.value ?: TextFieldValue()
+        val value = currentTextInputSession?.value ?: TextFieldCharSequence()
         val imeOptions = currentTextInputSession?.imeOptions ?: ImeOptions.Default
 
         logDebug { "createInputConnection.value = $value" }
@@ -177,8 +183,8 @@
         // endregion
 
         // region EditableTextInputSession
-        override val value: TextFieldValue
-            get() = state.value
+        override val value: TextFieldCharSequence
+            get() = state.text
 
         private var filter: TextEditFilter? = initialFilter
 
@@ -386,7 +392,7 @@
 /**
  * Fills necessary info of EditorInfo.
  */
-internal fun EditorInfo.update(textFieldValue: TextFieldValue, imeOptions: ImeOptions) {
+internal fun EditorInfo.update(textFieldValue: TextFieldCharSequence, imeOptions: ImeOptions) {
     this.imeOptions = when (imeOptions.imeAction) {
         ImeAction.Default -> {
             if (imeOptions.singleLine) {
@@ -466,10 +472,10 @@
         }
     }
 
-    this.initialSelStart = textFieldValue.selection.start
-    this.initialSelEnd = textFieldValue.selection.end
+    this.initialSelStart = textFieldValue.selectionInChars.start
+    this.initialSelEnd = textFieldValue.selectionInChars.end
 
-    EditorInfoCompat.setInitialSurroundingText(this, textFieldValue.text)
+    EditorInfoCompat.setInitialSurroundingText(this, textFieldValue)
 
     this.imeOptions = this.imeOptions or EditorInfo.IME_FLAG_NO_FULLSCREEN
 }
@@ -477,7 +483,7 @@
 private fun hasFlag(bits: Int, flag: Int): Boolean = (bits and flag) == flag
 
 private fun logDebug(tag: String = TAG, content: () -> String) {
-    if (DEBUG) {
+    if (TIA_DEBUG) {
         Log.d(tag, content())
     }
 }
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
index c9e129a..1649497 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/ChangeTracker.kt
@@ -19,7 +19,7 @@
 package androidx.compose.foundation.text2.input.internal
 
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.text2.input.MutableTextFieldValue.ChangeList
+import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.ui.text.TextRange
 
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt
index 13f8c84..a089951 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessor.kt
@@ -17,8 +17,10 @@
 package androidx.compose.foundation.text2.input.internal
 
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.text2.input.MutableTextFieldValueWithSelection
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.runtime.State
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -39,24 +41,24 @@
  */
 @OptIn(ExperimentalFoundationApi::class)
 internal class EditProcessor(
-    initialValue: TextFieldValue = TextFieldValue(
-        EmptyAnnotatedString,
-        TextRange.Zero,
-        null
-    ),
+    initialValue: TextFieldCharSequence = TextFieldCharSequence("", TextRange.Zero),
 ) {
 
+    private val valueMutableState = mutableStateOf(initialValue)
+
     /**
-     * The current state of the internal editing buffer as a [TextFieldValue] backed by Snapshot
-     * state, so its readers can get updates in composition context.
+     * The current state of the internal editing buffer as a [TextFieldCharSequence] backed by
+     * snapshot state, so its readers can get updates in composition context.
      */
-    var value: TextFieldValue by mutableStateOf(initialValue)
+    var value: TextFieldCharSequence by valueMutableState
         private set
 
+    val valueState: State<TextFieldCharSequence> get() = valueMutableState
+
     // The editing buffer used for applying editor commands from IME.
     internal var mBuffer: EditingBuffer = EditingBuffer(
-        text = initialValue.annotatedString,
-        selection = initialValue.selection
+        text = initialValue.toString(),
+        selection = initialValue.selectionInChars
     )
         private set
 
@@ -85,8 +87,8 @@
      * gain a new responsibility in the cases where developer filters the input or adds a template.
      * This would again introduce a need for sync between internal buffer and the state value.
      */
-    fun reset(newValue: TextFieldValue) {
-        val bufferState = TextFieldValue(
+    fun reset(newValue: TextFieldCharSequence) {
+        val bufferState = TextFieldCharSequence(
             mBuffer.toString(),
             mBuffer.selection,
             mBuffer.composition
@@ -94,21 +96,21 @@
 
         var textChanged = false
         var selectionChanged = false
-        val compositionChanged = newValue.composition != mBuffer.composition
+        val compositionChanged = newValue.compositionInChars != mBuffer.composition
 
-        if (bufferState.annotatedString != newValue.annotatedString) {
+        if (!bufferState.contentEquals(newValue)) {
             // reset the buffer in its entirety
             mBuffer = EditingBuffer(
-                text = newValue.annotatedString,
-                selection = newValue.selection
+                text = newValue.toString(),
+                selection = newValue.selectionInChars
             )
             textChanged = true
-        } else if (bufferState.selection != newValue.selection) {
-            mBuffer.setSelection(newValue.selection.min, newValue.selection.max)
+        } else if (bufferState.selectionInChars != newValue.selectionInChars) {
+            mBuffer.setSelection(newValue.selectionInChars.min, newValue.selectionInChars.max)
             selectionChanged = true
         }
 
-        val composition = newValue.composition
+        val composition = newValue.compositionInChars
         if (composition == null || composition.collapsed) {
             mBuffer.commitComposition()
         } else {
@@ -119,12 +121,10 @@
         //  communicate composing region changes back to IME.
         if (textChanged || (!selectionChanged && compositionChanged)) {
             mBuffer.commitComposition()
-            newValue.copy(composition = null)
         }
 
-        val finalValue = TextFieldValue(
-            // do not call toString on current buffer unnecessarily.
-            if (textChanged) newValue.annotatedString else bufferState.annotatedString,
+        val finalValue = TextFieldCharSequence(
+            if (textChanged) newValue else bufferState,
             mBuffer.selection,
             mBuffer.composition
         )
@@ -156,8 +156,8 @@
             throw RuntimeException(generateBatchErrorMessage(editCommands, lastCommand), e)
         }
 
-        val proposedValue = TextFieldValue(
-            annotatedString = mBuffer.toAnnotatedString(),
+        val proposedValue = TextFieldCharSequence(
+            text = mBuffer.toString(),
             selection = mBuffer.selection,
             composition = mBuffer.composition
         )
@@ -168,14 +168,15 @@
             value = proposedValue
         } else {
             val oldValue = value
-            val mutableValue = MutableTextFieldValueWithSelection(
-                proposedValue,
+            val mutableValue = TextFieldBufferWithSelection(
+                value = proposedValue,
+                sourceValue = oldValue,
                 initialChanges = mBuffer.changeTracker
             )
-            filter.filter(oldState = oldValue, newState = mutableValue)
+            filter.filter(originalValue = oldValue, valueWithChanges = mutableValue)
             // If neither the text nor the selection changed, we want to preserve the composition.
             // Otherwise, the IME will reset it anyway.
-            val newValue = mutableValue.toTextFieldValue(proposedValue.composition)
+            val newValue = mutableValue.toTextFieldCharSequence(proposedValue.compositionInChars)
             if (newValue == proposedValue) {
                 value = newValue
             } else {
@@ -218,7 +219,7 @@
      */
     internal fun interface ResetListener {
 
-        fun onReset(oldValue: TextFieldValue, newValue: TextFieldValue)
+        fun onReset(oldValue: TextFieldCharSequence, newValue: TextFieldCharSequence)
     }
 }
 
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt
index 3cda379..3ca9a3a 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/StatelessInputConnection.kt
@@ -28,13 +28,17 @@
 import android.view.inputmethod.ExtractedTextRequest
 import android.view.inputmethod.InputConnection
 import android.view.inputmethod.InputContentInfo
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
+import androidx.compose.ui.text.TextRange
+import androidx.annotation.VisibleForTesting
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.text.input.getSelectedText
-import androidx.compose.ui.text.input.getTextAfterSelection
-import androidx.compose.ui.text.input.getTextBeforeSelection
+import kotlin.math.max
+import kotlin.math.min
 
-private const val DEBUG = false
+@VisibleForTesting
+internal const val SIC_DEBUG = false
 private const val TAG = "StatelessIC"
 private const val DEBUG_CLASS = "StatelessInputConnection"
 
@@ -45,6 +49,7 @@
  * [AndroidTextInputAdapter]. InputConnections are requested and used by framework to create bridge
  * from IME to an active editor.
  */
+@OptIn(ExperimentalFoundationApi::class)
 internal class StatelessInputConnection(
     private val activeSessionProvider: () -> EditableTextInputSession?
 ) : InputConnection {
@@ -62,15 +67,15 @@
      * The input state from the currently active [TextInputSession] in
      * [AndroidTextInputAdapter]. Returns null if there is no active session.
      */
-    private val valueOrNull: TextFieldValue?
+    private val valueOrNull: TextFieldCharSequence?
         get() = activeSessionProvider()?.value
 
     /**
      * The input state from the currently active [TextInputSession] in
      * [AndroidTextInputAdapter]. Returns empty TextFieldValue if there is no active session.
      */
-    private val value: TextFieldValue
-        get() = valueOrNull ?: EmptyTextFieldValue
+    private val value: TextFieldCharSequence
+        get() = valueOrNull ?: TextFieldCharSequence()
 
     /**
      * Recording of editing operations for batch editing
@@ -219,7 +224,7 @@
 
     override fun getSelectedText(flags: Int): CharSequence? {
         // https://source.chromium.org/chromium/chromium/src/+/master:content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java;l=56;drc=0e20d1eb38227949805a4c0e9d5cdeddc8d23637
-        val result: CharSequence? = if (value.selection.collapsed) {
+        val result: CharSequence? = if (value.selectionInChars.collapsed) {
             null
         } else {
             // TODO(b/135556699) should return styled text
@@ -247,7 +252,7 @@
 
     override fun getCursorCapsMode(reqModes: Int): Int {
         logDebug("getCursorCapsMode($reqModes)")
-        return TextUtils.getCapsMode(value.text, value.selection.min, reqModes)
+        return TextUtils.getCapsMode(value, value.selectionInChars.min, reqModes)
     }
 
     // endregion
@@ -258,7 +263,7 @@
         logDebug("performContextMenuAction($id)")
         when (id) {
             android.R.id.selectAll -> {
-                addEditCommandWithBatch(SetSelectionCommand(0, value.text.length))
+                addEditCommandWithBatch(SetSelectionCommand(0, value.length))
             }
             // TODO(siyamed): Need proper connection to cut/copy/paste
             android.R.id.cut -> sendSynthesizedKeyEvent(KeyEvent.KEYCODE_CUT)
@@ -360,21 +365,50 @@
 
     // endregion
 
+    /**
+     * Returns the text before the selection.
+     *
+     * @param maxChars maximum number of characters (inclusive) before the minimum value in
+     * [TextFieldCharSequence.selectionInChars].
+     *
+     * @see TextRange.min
+     */
+    fun TextFieldCharSequence.getTextBeforeSelection(maxChars: Int): CharSequence =
+        subSequence(max(0, selectionInChars.min - maxChars), selectionInChars.min)
+
+    /**
+     * Returns the text after the selection.
+     *
+     * @param maxChars maximum number of characters (exclusive) after the maximum value in
+     * [TextFieldCharSequence.selectionInChars].
+     *
+     * @see TextRange.max
+     */
+    fun TextFieldCharSequence.getTextAfterSelection(maxChars: Int): CharSequence =
+        subSequence(selectionInChars.max, min(selectionInChars.max + maxChars, length))
+
+    /**
+     * Returns the currently selected text.
+     */
+    fun TextFieldCharSequence.getSelectedText(): CharSequence =
+        subSequence(selectionInChars.min, selectionInChars.max)
+
     private fun logDebug(message: String) {
-        if (DEBUG) {
+        if (SIC_DEBUG) {
             Log.d(TAG, "$DEBUG_CLASS.$message, $isICActive, ${activeSessionProvider() != null}")
         }
     }
 }
 
-private fun TextFieldValue.toExtractedText(): ExtractedText {
+@OptIn(ExperimentalFoundationApi::class)
+private fun TextFieldCharSequence.toExtractedText(): ExtractedText {
     val res = ExtractedText()
-    res.text = text
+    res.text = this
     res.startOffset = 0
-    res.partialEndOffset = text.length
+    res.partialEndOffset = length
     res.partialStartOffset = -1 // -1 means full text
-    res.selectionStart = selection.min
-    res.selectionEnd = selection.max
-    res.flags = if ('\n' in text) 0 else ExtractedText.FLAG_SINGLE_LINE
+    res.selectionStart = selectionInChars.min
+    res.selectionEnd = selectionInChars.max
+    res.flags = if ('\n' in this) 0 else ExtractedText.FLAG_SINGLE_LINE
     return res
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt
index 6e32685..655d496 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldCoreModifier.kt
@@ -77,7 +77,7 @@
     private val cursorBrush: Brush,
     private val writeable: Boolean,
     private val scrollState: ScrollState,
-    private val orientation: Orientation
+    private val orientation: Orientation,
 ) : ModifierNodeElement<TextFieldCoreModifierNode>() {
 
     override fun create(): TextFieldCoreModifierNode = TextFieldCoreModifierNode(
@@ -87,7 +87,7 @@
         cursorBrush = cursorBrush,
         writable = writeable,
         scrollState = scrollState,
-        orientation = orientation
+        orientation = orientation,
     )
 
     override fun update(node: TextFieldCoreModifierNode): TextFieldCoreModifierNode {
@@ -98,7 +98,7 @@
             cursorBrush = cursorBrush,
             writeable = writeable,
             scrollState = scrollState,
-            orientation = orientation
+            orientation = orientation,
         )
         return node
     }
@@ -117,7 +117,7 @@
     private var cursorBrush: Brush,
     private var writable: Boolean,
     private var scrollState: ScrollState,
-    private var orientation: Orientation
+    private var orientation: Orientation,
 ) : Modifier.Node(),
     LayoutModifierNode,
     DrawModifierNode,
@@ -158,7 +158,7 @@
         cursorBrush: Brush,
         writeable: Boolean,
         scrollState: ScrollState,
-        orientation: Orientation
+        orientation: Orientation,
     ) {
         val wasFocused = this.isFocused
         val previousTextFieldState = this.textFieldState
@@ -181,7 +181,7 @@
             changeObserverJob = coroutineScope.launch {
                 // Animate the cursor even when animations are disabled by the system.
                 withContext(FixedMotionDurationScale) {
-                    snapshotFlow { textFieldState.value }
+                    snapshotFlow { textFieldState.text }
                         .collectLatest {
                             // ensure that the value is always 1f _this_ frame by calling snapTo
                             cursorAlpha.snapTo(1f)
@@ -204,14 +204,14 @@
 
     override fun ContentDrawScope.draw() {
         drawContent()
-        val value = textFieldState.value
+        val value = textFieldState.text
         val textLayoutResult = textLayoutState.layoutResult ?: return
 
-        if (value.selection.collapsed) {
+        if (value.selectionInChars.collapsed) {
             drawText(textLayoutResult)
-            drawCursor(value.selection, textLayoutResult)
+            drawCursor(value.selectionInChars, textLayoutResult)
         } else {
-            drawSelection(value.selection, textLayoutResult)
+            drawSelection(value.selectionInChars, textLayoutResult)
             drawText(textLayoutResult)
         }
     }
@@ -224,7 +224,7 @@
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
-        val currSelection = textFieldState.value.selection
+        val currSelection = textFieldState.text.selectionInChars
         val offsetToFollow = when {
             currSelection.start != previousSelection.start -> currSelection.start
             currSelection.end != previousSelection.end -> currSelection.end
@@ -260,13 +260,13 @@
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
-        val value = textFieldState.value
+        val value = textFieldState.text
         val offsetToFollow = when {
-            value.selection.start != previousSelection.start -> value.selection.start
-            value.selection.end != previousSelection.end -> value.selection.end
-            else -> value.selection.min
+            value.selectionInChars.start != previousSelection.start -> value.selectionInChars.start
+            value.selectionInChars.end != previousSelection.end -> value.selectionInChars.end
+            else -> value.selectionInChars.min
         }
-        previousSelection = value.selection
+        previousSelection = value.selectionInChars
 
         // If the maxIntrinsicWidth of the children is already smaller than the constraint, pass
         // the original constraints so that the children has more information to determine its
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt
index 4817e64..b1955d7 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldDecoratorModifier.kt
@@ -17,14 +17,15 @@
 package androidx.compose.foundation.text2.input.internal
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.detectTapAndPress
 import androidx.compose.foundation.text.KeyboardActionScope
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text2.BasicTextField2
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.deselect
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusDirection
 import androidx.compose.ui.focus.FocusEventModifierNode
 import androidx.compose.ui.focus.FocusManager
@@ -35,9 +36,10 @@
 import androidx.compose.ui.input.key.KeyInputModifierNode
 import androidx.compose.ui.input.pointer.PointerEvent
 import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.input.pointer.changedToDown
+import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
 import androidx.compose.ui.layout.LayoutCoordinates
 import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.GlobalPositionAwareModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.node.PointerInputModifierNode
@@ -59,9 +61,9 @@
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.input.ImeAction
-import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.KeyboardCapitalization
+import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.util.fastAny
 
 /**
  * Modifier element for most of the functionality of [BasicTextField2] that is attached to the
@@ -80,7 +82,7 @@
     private val readOnly: Boolean,
     private val keyboardOptions: KeyboardOptions,
     private val keyboardActions: KeyboardActions,
-    private val singleLine: Boolean
+    private val singleLine: Boolean,
 ) : ModifierNodeElement<TextFieldDecoratorModifierNode>() {
     override fun create(): TextFieldDecoratorModifierNode = TextFieldDecoratorModifierNode(
         textFieldState = textFieldState,
@@ -91,7 +93,7 @@
         readOnly = readOnly,
         keyboardOptions = keyboardOptions,
         keyboardActions = keyboardActions,
-        singleLine = singleLine
+        singleLine = singleLine,
     )
 
     override fun update(node: TextFieldDecoratorModifierNode): TextFieldDecoratorModifierNode {
@@ -104,7 +106,7 @@
             readOnly = readOnly,
             keyboardOptions = keyboardOptions,
             keyboardActions = keyboardActions,
-            singleLine = singleLine
+            singleLine = singleLine,
         )
         return node
     }
@@ -123,10 +125,10 @@
     var filter: TextEditFilter?,
     var enabled: Boolean,
     var readOnly: Boolean,
-    var keyboardOptions: KeyboardOptions,
+    keyboardOptions: KeyboardOptions,
     var keyboardActions: KeyboardActions,
-    var singleLine: Boolean
-) : Modifier.Node(),
+    var singleLine: Boolean,
+) : DelegatingNode(),
     SemanticsModifierNode,
     FocusRequesterModifierNode,
     FocusEventModifierNode,
@@ -135,8 +137,24 @@
     KeyInputModifierNode,
     CompositionLocalConsumerModifierNode {
 
+    private val pointerInputNode = SuspendingPointerInputModifierNode {
+        detectTapAndPress(onTap = {
+            if (!isFocused) {
+                requestFocus()
+            } else if (enabled && !readOnly) {
+                textInputSession?.showSoftwareKeyboard()
+            }
+        })
+    }
+        // TODO: remove `.node` after aosp/2462416 lands and merge everything into one delegated
+        //  block
+        .also { delegated { it.node } }
+
+    var keyboardOptions: KeyboardOptions = keyboardOptions.withDefaultsFrom(filter?.keyboardOptions)
+        private set
+
     // semantics properties that require semantics invalidation
-    private var lastText: AnnotatedString? = null
+    private var lastText: CharSequence? = null
     private var lastSelection: TextRange? = null
     private var lastEnabled: Boolean = enabled
 
@@ -200,12 +218,13 @@
         readOnly: Boolean,
         keyboardOptions: KeyboardOptions,
         keyboardActions: KeyboardActions,
-        singleLine: Boolean
+        singleLine: Boolean,
     ) {
         // Find the diff: current previous and new values before updating current.
         val previousWriteable = this.enabled && !this.readOnly
         val writeable = enabled && !readOnly
         val previousTextFieldState = this.textFieldState
+        val previousKeyboardOptions = this.keyboardOptions
 
         // Apply the diff.
         this.textFieldState = textFieldState
@@ -214,19 +233,22 @@
         this.filter = filter
         this.enabled = enabled
         this.readOnly = readOnly
-        this.keyboardOptions = keyboardOptions
+        this.keyboardOptions = keyboardOptions.withDefaultsFrom(filter?.keyboardOptions)
         this.keyboardActions = keyboardActions
         this.singleLine = singleLine
 
         // React to diff.
         // If made writable while focused, or we got a completely new state instance,
         // start a new input session.
-        if (previousWriteable != writeable || textFieldState != previousTextFieldState) {
+        if (writeable != previousWriteable ||
+            textFieldState != previousTextFieldState ||
+            keyboardOptions != previousKeyboardOptions
+        ) {
             if (writeable && isFocused) {
                 // The old session will be implicitly disposed.
                 textInputSession = textInputAdapter?.startInputSession(
                     textFieldState,
-                    keyboardOptions.toImeOptions(singleLine),
+                    this.keyboardOptions.toImeOptions(singleLine),
                     filter,
                     onImeActionPerformed
                 )
@@ -246,15 +268,15 @@
     override val semanticsConfiguration: SemanticsConfiguration
         get() {
             var localSemantics = semanticsConfigurationCache
-            val value = textFieldState.value
+            val value = textFieldState.text
             // Cache invalidation is done here instead of only in updateNode because the text or
             // selection might change without triggering a modifier update.
             if (localSemantics == null ||
-                lastText != value.annotatedString ||
-                lastSelection != value.selection ||
+                !value.contentEquals(lastText) ||
+                lastSelection != value.selectionInChars ||
                 lastEnabled != enabled
             ) {
-                localSemantics = generateSemantics(value.annotatedString, value.selection)
+                localSemantics = generateSemantics(value, value.selectionInChars)
             }
             return localSemantics
         }
@@ -293,13 +315,11 @@
         pass: PointerEventPass,
         bounds: IntSize
     ) {
-        if (pass == PointerEventPass.Main && pointerEvent.changes.fastAny { it.changedToDown() }) {
-            requestFocus()
-        }
+        pointerInputNode.onPointerEvent(pointerEvent, pass, bounds)
     }
 
     override fun onCancelPointerInput() {
-        // Nothing to do yet, since onPointerEvent isn't handling any gestures.
+        pointerInputNode.onCancelPointerInput()
     }
 
     override fun onPreKeyEvent(event: KeyEvent): Boolean {
@@ -319,7 +339,7 @@
     }
 
     private fun generateSemantics(
-        text: AnnotatedString,
+        text: CharSequence,
         selection: TextRange
     ): SemanticsConfiguration {
         lastText = text
@@ -330,7 +350,7 @@
             getTextLayoutResult {
                 textLayoutState.layoutResult?.let { result -> it.add(result) } ?: false
             }
-            editableText = text
+            editableText = AnnotatedString(text.toString())
             textSelectionRange = selection
             imeAction = keyboardOptions.imeAction
             if (!enabled) disabled()
@@ -359,8 +379,8 @@
                 ) {
                     // reset is required to make sure IME gets the update.
                     textFieldState.editProcessor.reset(
-                        TextFieldValue(
-                            annotatedString = text,
+                        TextFieldCharSequence(
+                            text = textFieldState.text,
                             selection = TextRange(start, end)
                         )
                     )
@@ -401,4 +421,34 @@
         textInputSession?.dispose()
         textInputSession = null
     }
+}
+
+/**
+ * Returns a [KeyboardOptions] that is merged with [defaults], with this object's values taking
+ * precedence.
+ */
+// TODO KeyboardOptions can't actually be merged correctly in all cases, because its properties
+//  don't all have proper "unspecified" values. I think we can fix that in a backwards-compatible
+//  way, but it will require adding new API outside of the text2 package so we should hold off on
+//  making them until after the study.
+internal fun KeyboardOptions.withDefaultsFrom(defaults: KeyboardOptions?): KeyboardOptions {
+    if (defaults == null) return this
+    return KeyboardOptions(
+        capitalization = if (this.capitalization != KeyboardCapitalization.None) {
+            this.capitalization
+        } else {
+            defaults.capitalization
+        },
+        autoCorrect = this.autoCorrect && defaults.autoCorrect,
+        keyboardType = if (this.keyboardType != KeyboardType.Text) {
+            this.keyboardType
+        } else {
+            defaults.keyboardType
+        },
+        imeAction = if (this.imeAction != ImeAction.Default) {
+            this.imeAction
+        } else {
+            defaults.imeAction
+        }
+    )
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt
index 6cbe4e0..eacb620 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextFieldKeyEventHandler.kt
@@ -26,6 +26,7 @@
 import androidx.compose.foundation.text2.input.TextEditFilter
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.internal.TextFieldPreparedSelection.Companion.NoCharacterFound
+import androidx.compose.foundation.text2.input.selectCharsIn
 import androidx.compose.ui.input.key.KeyEvent
 import androidx.compose.ui.input.key.KeyEventType
 import androidx.compose.ui.input.key.type
@@ -216,12 +217,12 @@
             textPreparedSelectionState = preparedSelectionState
         )
         preparedSelection.block()
-        if (preparedSelection.selection != preparedSelection.initialValue.selection) {
+        if (preparedSelection.selection != preparedSelection.initialValue.selectionInChars) {
             // update the editProcessor with the latest selection state.
             // this has to be a reset because EditCommands do not inform IME.
-            state.editProcessor.reset(
-                preparedSelection.initialValue.copy(selection = preparedSelection.selection)
-            )
+            state.edit {
+                selectCharsIn(preparedSelection.selection)
+            }
         }
     }
 
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt
index 2fad817..a916c38 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextInputSession.kt
@@ -22,6 +22,7 @@
 import android.view.inputmethod.InputConnection
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.ImeOptions
@@ -75,7 +76,7 @@
      * The current [TextFieldValue] in this input session. This value is typically supplied by a
      * backing [TextFieldState] that is used to initialize the session.
      */
-    val value: TextFieldValue
+    val value: TextFieldCharSequence
 
     /**
      * Callback to execute for InputConnection to communicate the changes requested by the IME.
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt
index 3a42b3b..ff503ef 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextLayoutState.kt
@@ -82,7 +82,10 @@
                 onTextLayout(it)
             }
             layoutResult = it
-            proxy = TextLayoutResultProxy(it)
+            proxy = TextLayoutResultProxy(it).apply {
+                decorationBoxCoordinates = proxy?.decorationBoxCoordinates
+                innerTextFieldCoordinates = proxy?.innerTextFieldCoordinates
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt
index ebaefa8..9bc6d85 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/input/internal/TextPreparedSelection.kt
@@ -29,6 +29,7 @@
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.style.ResolvedTextDirection
+import kotlin.math.abs
 
 /**
  * [TextFieldPreparedSelection] provides a scope for many selection-related operations. However,
@@ -77,17 +78,17 @@
      * [TextFieldPreparedSelection]. It is also used to make comparison between the initial state
      * and the modified state of selection and content.
      */
-    val initialValue = Snapshot.withoutReadObservation { state.value }
+    val initialValue = Snapshot.withoutReadObservation { state.text }
 
     /**
      * Current active selection in the context of this [TextFieldPreparedSelection]
      */
-    var selection = initialValue.selection
+    var selection = initialValue.selectionInChars
 
     /**
      * Initial text value.
      */
-    private val text = initialValue.text
+    private val text: String = initialValue.toString()
 
     /**
      * If there is a non-collapsed selection, delete its contents. Or execute the given [or] block.
@@ -128,11 +129,22 @@
         val visibleInnerTextFieldRect = innerTextFieldCoordinates?.let { inner ->
             decorationBoxCoordinates?.localBoundingBoxOf(inner)
         } ?: Rect.Zero
-        val currentOffset = initialValue.selection.end
+        val currentOffset = initialValue.selectionInChars.end
         val currentPos = value.getCursorRect(currentOffset)
-        val x = currentPos.left
-        val y = currentPos.top + visibleInnerTextFieldRect.size.height * pagesAmount
-        return value.getOffsetForPosition(Offset(x, y))
+        val newPos = currentPos.translate(
+            translateX = 0f,
+            translateY = visibleInnerTextFieldRect.size.height * pagesAmount
+        )
+        // which line does the new cursor position belong?
+        val topLine = value.getLineForVerticalPosition(newPos.top)
+        val lineSeparator = value.getLineBottom(topLine)
+        return if (abs(newPos.top - lineSeparator) > abs(newPos.bottom - lineSeparator)) {
+            // most of new cursor is on top line
+            value.getOffsetForPosition(newPos.topLeft)
+        } else {
+            // most of new cursor is on bottom line
+            value.getOffsetForPosition(newPos.bottomLeft)
+        }
     }
 
     /**
@@ -317,7 +329,7 @@
 
     // it selects a text from the original selection start to a current selection end
     fun selectMovement() = applyIfNotEmpty(false) {
-        selection = TextRange(initialValue.selection.start, selection.end)
+        selection = TextRange(initialValue.selectionInChars.start, selection.end)
     }
 
     private fun isLtr(): Boolean {
@@ -328,8 +340,8 @@
     private tailrec fun TextLayoutResult.getNextWordOffsetForLayout(
         currentOffset: Int = selection.end
     ): Int {
-        if (currentOffset >= initialValue.text.length) {
-            return initialValue.text.length
+        if (currentOffset >= initialValue.length) {
+            return initialValue.length
         }
         val currentWord = getWordBoundary(charOffset(currentOffset))
         return if (currentWord.end <= currentOffset) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
index a5cf564..b25a9cd 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.geometry.Offset
@@ -36,10 +35,15 @@
 import androidx.compose.ui.input.key.KeyEvent
 import androidx.compose.ui.input.key.key
 import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.PointerInputScope
+import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
 import androidx.compose.ui.modifier.ModifierLocalNode
 import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.PointerInputModifierNode
 import androidx.compose.ui.node.SemanticsModifierNode
 import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.platform.debugInspectorInfo
@@ -49,6 +53,7 @@
 import androidx.compose.ui.semantics.onClick
 import androidx.compose.ui.semantics.onLongClick
 import androidx.compose.ui.semantics.role
+import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.center
 import androidx.compose.ui.unit.toOffset
 import kotlinx.coroutines.CoroutineScope
@@ -136,40 +141,28 @@
     onClick: () -> Unit
 ) = composed(
     factory = {
-        val onClickState = rememberUpdatedState(onClick)
         val pressInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
         val currentKeyPressInteractions = remember { mutableMapOf<Key, PressInteraction.Press>() }
-        val delayPressInteraction = remember { mutableStateOf({ true }) }
+        val centreOffset = remember { mutableStateOf(Offset.Zero) }
+
         val interactionModifier = if (enabled) {
             ClickableInteractionElement(
                 interactionSource,
                 pressInteraction,
-                currentKeyPressInteractions,
-                delayPressInteraction
+                currentKeyPressInteractions
             )
         } else Modifier
 
-        val centreOffset = remember { mutableStateOf(Offset.Zero) }
+        val pointerInputModifier = ClickablePointerInputElement(
+            enabled,
+            interactionSource,
+            onClick,
+            centreOffset,
+            pressInteraction
+        )
 
-        val gesture = Modifier.pointerInput(interactionSource, enabled) {
-            centreOffset.value = size.center.toOffset()
-            detectTapAndPress(
-                onPress = { offset ->
-                    if (enabled) {
-                        handlePressInteraction(
-                            offset,
-                            interactionSource,
-                            pressInteraction,
-                            delayPressInteraction
-                        )
-                    }
-                },
-                onTap = { if (enabled) onClickState.value.invoke() }
-            )
-        }
         Modifier
             .genericClickableWithoutGesture(
-                gestureModifiers = gesture,
                 interactionSource = interactionSource,
                 indication = indication,
                 indicationScope = rememberCoroutineScope(),
@@ -182,6 +175,7 @@
                 onLongClick = null,
                 onClick = onClick
             )
+            .then(pointerInputModifier)
             .then(interactionModifier)
     },
     inspectorInfo = debugInspectorInfo {
@@ -294,11 +288,7 @@
     onClick: () -> Unit
 ) = composed(
     factory = {
-        val onClickState = rememberUpdatedState(onClick)
-        val onLongClickState = rememberUpdatedState(onLongClick)
-        val onDoubleClickState = rememberUpdatedState(onDoubleClick)
         val hasLongClick = onLongClick != null
-        val hasDoubleClick = onDoubleClick != null
         val pressInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
         val currentKeyPressInteractions = remember { mutableMapOf<Key, PressInteraction.Press>() }
         if (enabled) {
@@ -314,48 +304,27 @@
                 }
             }
         }
-        val delayPressInteraction = remember { mutableStateOf({ true }) }
+        val centreOffset = remember { mutableStateOf(Offset.Zero) }
         val interactionModifier = if (enabled) {
             ClickableInteractionElement(
                 interactionSource,
                 pressInteraction,
-                currentKeyPressInteractions,
-                delayPressInteraction
+                currentKeyPressInteractions
             )
         } else Modifier
 
-        val centreOffset = remember { mutableStateOf(Offset.Zero) }
+        val pointerInputModifier = CombinedClickablePointerInputElement(
+            enabled,
+            interactionSource,
+            onClick,
+            centreOffset,
+            pressInteraction,
+            onLongClick,
+            onDoubleClick
+        )
 
-        val gesture =
-            Modifier.pointerInput(interactionSource, hasLongClick, hasDoubleClick, enabled) {
-                centreOffset.value = size.center.toOffset()
-                detectTapGestures(
-                    onDoubleTap = if (hasDoubleClick && enabled) {
-                        { onDoubleClickState.value?.invoke() }
-                    } else {
-                        null
-                    },
-                    onLongPress = if (hasLongClick && enabled) {
-                        { onLongClickState.value?.invoke() }
-                    } else {
-                        null
-                    },
-                    onPress = { offset ->
-                        if (enabled) {
-                            handlePressInteraction(
-                                offset,
-                                interactionSource,
-                                pressInteraction,
-                                delayPressInteraction
-                            )
-                        }
-                    },
-                    onTap = { if (enabled) onClickState.value.invoke() }
-                )
-            }
         Modifier
             .genericClickableWithoutGesture(
-                gestureModifiers = gesture,
                 interactionSource = interactionSource,
                 indication = indication,
                 indicationScope = rememberCoroutineScope(),
@@ -368,6 +337,7 @@
                 onLongClick = onLongClick,
                 onClick = onClick
             )
+            .then(pointerInputModifier)
             .then(interactionModifier)
     },
     inspectorInfo = debugInspectorInfo {
@@ -388,11 +358,11 @@
     pressPoint: Offset,
     interactionSource: MutableInteractionSource,
     pressInteraction: MutableState<PressInteraction.Press?>,
-    delayPressInteraction: State<() -> Boolean>
+    delayPressInteraction: () -> Boolean
 ) {
     coroutineScope {
         val delayJob = launch {
-            if (delayPressInteraction.value()) {
+            if (delayPressInteraction()) {
                 delay(TapIndicationDelay)
             }
             val press = PressInteraction.Press(pressPoint)
@@ -456,7 +426,6 @@
 internal expect val KeyEvent.isClick: Boolean
 
 internal fun Modifier.genericClickableWithoutGesture(
-    gestureModifiers: Modifier,
     interactionSource: MutableInteractionSource,
     indication: Indication?,
     indicationScope: CoroutineScope,
@@ -508,7 +477,6 @@
             .indication(interactionSource, indication)
             .hoverable(enabled = enabled, interactionSource = interactionSource)
             .focusableInNonTouchMode(enabled = enabled, interactionSource = interactionSource)
-            .then(gestureModifiers)
 }
 
 private class ClickableSemanticsElement(
@@ -596,16 +564,14 @@
 
 // Only interactionSource should ever change - the rest must be remembered with no keys.
 private class ClickableInteractionElement(
-    private val interactionSource: MutableInteractionSource?,
+    private val interactionSource: MutableInteractionSource,
     private val pressInteraction: MutableState<PressInteraction.Press?>,
-    private val currentKeyPressInteractions: MutableMap<Key, PressInteraction.Press>,
-    private val delayPressInteraction: MutableState<() -> Boolean>
+    private val currentKeyPressInteractions: MutableMap<Key, PressInteraction.Press>
 ) : ModifierNodeElement<ClickableInteractionNode>() {
     override fun create(): ClickableInteractionNode = ClickableInteractionNode(
         interactionSource,
         pressInteraction,
-        currentKeyPressInteractions,
-        delayPressInteraction
+        currentKeyPressInteractions
     )
 
     override fun update(node: ClickableInteractionNode) = node.also {
@@ -622,46 +588,278 @@
     }
 
     override fun hashCode(): Int {
-        return interactionSource?.hashCode() ?: 0
+        return interactionSource.hashCode()
     }
 
     override fun InspectorInfo.inspectableProperties() = Unit
 }
 
 private class ClickableInteractionNode(
-    private var interactionSource: MutableInteractionSource?,
+    private var interactionSource: MutableInteractionSource,
     private val pressInteraction: MutableState<PressInteraction.Press?>,
-    private val currentKeyPressInteractions: MutableMap<Key, PressInteraction.Press>,
-    private val delayPressInteraction: MutableState<() -> Boolean>
-) : Modifier.Node(), ModifierLocalNode, CompositionLocalConsumerModifierNode {
-    fun updateInteractionSource(interactionSource: MutableInteractionSource?) {
+    private val currentKeyPressInteractions: MutableMap<Key, PressInteraction.Press>
+) : Modifier.Node() {
+    fun updateInteractionSource(interactionSource: MutableInteractionSource) {
         if (this.interactionSource != interactionSource) {
             disposeInteractionSource()
             this.interactionSource = interactionSource
         }
     }
 
-    override fun onAttach() {
-        delayPressInteraction.value = {
-            ModifierLocalScrollableContainer.current || isComposeRootInScrollableContainer()
-        }
-    }
-
     override fun onDetach() {
         disposeInteractionSource()
     }
 
     private fun disposeInteractionSource() {
-        interactionSource?.let { interactionSource ->
-            pressInteraction.value?.let { oldValue ->
-                val interaction = PressInteraction.Cancel(oldValue)
-                interactionSource.tryEmit(interaction)
-            }
-            currentKeyPressInteractions.values.forEach {
-                interactionSource.tryEmit(PressInteraction.Cancel(it))
-            }
+        pressInteraction.value?.let { oldValue ->
+            val interaction = PressInteraction.Cancel(oldValue)
+            interactionSource.tryEmit(interaction)
+        }
+        currentKeyPressInteractions.values.forEach {
+            interactionSource.tryEmit(PressInteraction.Cancel(it))
         }
         pressInteraction.value = null
         currentKeyPressInteractions.clear()
     }
 }
+
+private class ClickablePointerInputElement(
+    private val enabled: Boolean,
+    private val interactionSource: MutableInteractionSource,
+    private val onClick: () -> Unit,
+    private val centreOffset: MutableState<Offset>,
+    private val pressInteraction: MutableState<PressInteraction.Press?>
+) : ModifierNodeElement<ClickablePointerInputNode>() {
+    override fun create(): ClickablePointerInputNode = ClickablePointerInputNode(
+        enabled,
+        interactionSource,
+        onClick,
+        centreOffset,
+        pressInteraction
+    )
+
+    override fun update(node: ClickablePointerInputNode) = node.also {
+        it.updateParameters(enabled, interactionSource, onClick)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is ClickablePointerInputElement) return false
+
+        if (enabled != other.enabled) return false
+        if (interactionSource != other.interactionSource) return false
+        if (onClick != other.onClick) return false
+
+        return true
+    }
+
+    override fun InspectorInfo.inspectableProperties() = Unit
+
+    override fun hashCode(): Int {
+        var result = enabled.hashCode()
+        result = 31 * result + interactionSource.hashCode()
+        result = 31 * result + onClick.hashCode()
+        return result
+    }
+}
+
+private class CombinedClickablePointerInputElement(
+    private val enabled: Boolean,
+    private val interactionSource: MutableInteractionSource,
+    private val onClick: () -> Unit,
+    private val centreOffset: MutableState<Offset>,
+    private val pressInteraction: MutableState<PressInteraction.Press?>,
+    private val onLongClick: (() -> Unit)?,
+    private val onDoubleClick: (() -> Unit)?
+) : ModifierNodeElement<CombinedClickablePointerInputNode>() {
+    override fun create(): CombinedClickablePointerInputNode = CombinedClickablePointerInputNode(
+        enabled,
+        interactionSource,
+        onClick,
+        centreOffset,
+        pressInteraction,
+        onLongClick,
+        onDoubleClick
+    )
+
+    override fun update(node: CombinedClickablePointerInputNode) = node.also {
+        it.updateParameters(enabled, interactionSource, onClick, onLongClick, onDoubleClick)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is CombinedClickablePointerInputElement) return false
+
+        if (enabled != other.enabled) return false
+        if (interactionSource != other.interactionSource) return false
+        if (onClick != other.onClick) return false
+        if (onLongClick != other.onLongClick) return false
+        if (onDoubleClick != other.onDoubleClick) return false
+
+        return true
+    }
+
+    override fun InspectorInfo.inspectableProperties() = Unit
+
+    override fun hashCode(): Int {
+        var result = enabled.hashCode()
+        result = 31 * result + interactionSource.hashCode()
+        result = 31 * result + onClick.hashCode()
+        result = 31 * result + (onLongClick?.hashCode() ?: 0)
+        result = 31 * result + (onDoubleClick?.hashCode() ?: 0)
+        return result
+    }
+}
+
+private sealed class AbstractClickablePointerInputNode(
+    protected var enabled: Boolean,
+    protected var interactionSource: MutableInteractionSource?,
+    protected var onClick: () -> Unit,
+    protected val centreOffset: MutableState<Offset>,
+    private val pressInteraction: MutableState<PressInteraction.Press?>,
+) : DelegatingNode(), ModifierLocalNode, CompositionLocalConsumerModifierNode,
+    PointerInputModifierNode {
+
+    private val delayPressInteraction = {
+        ModifierLocalScrollableContainer.current || isComposeRootInScrollableContainer()
+    }
+
+    private val pointerInputNode = SuspendingPointerInputModifierNode { pointerInput() }
+        // TODO: remove `.node` after aosp/2462416 lands and merge everything into one delegated
+        //  block
+        .also { delegated { it.node } }
+
+    protected abstract suspend fun PointerInputScope.pointerInput()
+
+    override fun onPointerEvent(
+        pointerEvent: PointerEvent,
+        pass: PointerEventPass,
+        bounds: IntSize
+    ) {
+        pointerInputNode.onPointerEvent(pointerEvent, pass, bounds)
+    }
+
+    override fun onCancelPointerInput() {
+        pointerInputNode.onCancelPointerInput()
+    }
+
+    protected suspend fun PressGestureScope.handlePressInteraction(offset: Offset) {
+        interactionSource?.let { interactionSource ->
+            handlePressInteraction(
+                offset,
+                interactionSource,
+                pressInteraction,
+                delayPressInteraction
+            )
+        }
+    }
+
+    protected fun resetPointerInputHandler() = pointerInputNode.resetPointerInputHandler()
+}
+
+private class ClickablePointerInputNode(
+    enabled: Boolean,
+    interactionSource: MutableInteractionSource,
+    onClick: () -> Unit,
+    centreOffset: MutableState<Offset>,
+    pressInteraction: MutableState<PressInteraction.Press?>
+) : AbstractClickablePointerInputNode(
+    enabled,
+    interactionSource,
+    onClick,
+    centreOffset,
+    pressInteraction
+) {
+    override suspend fun PointerInputScope.pointerInput() {
+        centreOffset.value = size.center.toOffset()
+        detectTapAndPress(
+            onPress = { offset ->
+                if (enabled) {
+                    handlePressInteraction(offset)
+                }
+            },
+            onTap = { if (enabled) onClick() }
+        )
+    }
+
+    fun updateParameters(
+        enabled: Boolean,
+        interactionSource: MutableInteractionSource,
+        onClick: () -> Unit,
+    ) {
+        // These are captured inside callbacks, not as an input to detectTapGestures,
+        // so no need need to reset pointer input handling
+        this.enabled = enabled
+        this.onClick = onClick
+        this.interactionSource = interactionSource
+    }
+}
+
+private class CombinedClickablePointerInputNode(
+    enabled: Boolean,
+    interactionSource: MutableInteractionSource,
+    onClick: () -> Unit,
+    centreOffset: MutableState<Offset>,
+    pressInteraction: MutableState<PressInteraction.Press?>,
+    private var onLongClick: (() -> Unit)?,
+    private var onDoubleClick: (() -> Unit)?
+) : AbstractClickablePointerInputNode(
+    enabled,
+    interactionSource,
+    onClick,
+    centreOffset,
+    pressInteraction
+) {
+    override suspend fun PointerInputScope.pointerInput() {
+        centreOffset.value = size.center.toOffset()
+        detectTapGestures(
+            onDoubleTap = if (enabled && onDoubleClick != null) {
+                { onDoubleClick?.invoke() }
+            } else null,
+            onLongPress = if (enabled && onLongClick != null) {
+                { onLongClick?.invoke() }
+            } else null,
+            onPress = { offset ->
+                if (enabled) {
+                    handlePressInteraction(offset)
+                }
+            },
+            onTap = { if (enabled) onClick() }
+        )
+    }
+
+    fun updateParameters(
+        enabled: Boolean,
+        interactionSource: MutableInteractionSource,
+        onClick: () -> Unit,
+        onLongClick: (() -> Unit)?,
+        onDoubleClick: (() -> Unit)?
+    ) {
+        // These are captured inside callbacks, not as an input to detectTapGestures,
+        // so no need need to reset pointer input handling
+        this.onClick = onClick
+        this.interactionSource = interactionSource
+
+        var changed = false
+
+        // This is captured as a parameter to detectTapGestures, so we need to restart detecting
+        // gestures if it changes.
+        if (this.enabled != enabled) {
+            this.enabled = enabled
+            changed = true
+        }
+
+        // We capture these inside the callback, so if the lambda changes value we don't want to
+        // reset input handling - only reset if they go from not-defined to defined, and vice-versa,
+        // as that is what is captured in the parameter to detectTapGestures.
+        if ((this.onLongClick == null) != (onLongClick == null)) {
+            changed = true
+        }
+        this.onLongClick = onLongClick
+        if ((this.onDoubleClick == null) != (onDoubleClick == null)) {
+            changed = true
+        }
+        this.onDoubleClick = onDoubleClick
+        if (changed) resetPointerInputHandler()
+    }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index 54ce08b..ccc1466 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -45,11 +45,16 @@
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.input.pointer.AwaitPointerEventScope
 import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.PointerEventPass
 import androidx.compose.ui.input.pointer.PointerEventType
 import androidx.compose.ui.input.pointer.PointerType
-import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
 import androidx.compose.ui.modifier.ModifierLocalProvider
 import androidx.compose.ui.modifier.modifierLocalOf
+import androidx.compose.ui.node.DelegatingNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.PointerInputModifierNode
+import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.unit.Density
@@ -280,31 +285,81 @@
         },
         canDrag = { down -> down.type != PointerType.Mouse }
     )
-        .mouseWheelScroll(scrollLogic, scrollConfig)
+        .then(MouseWheelScrollElement(scrollLogic, scrollConfig))
         .nestedScroll(nestedScrollConnection, nestedScrollDispatcher.value)
 }
 
-private fun Modifier.mouseWheelScroll(
-    scrollingLogicState: State<ScrollingLogic>,
-    mouseWheelScrollConfig: ScrollConfig,
-) = pointerInput(scrollingLogicState, mouseWheelScrollConfig) {
-    awaitPointerEventScope {
-        while (true) {
-            val event = awaitScrollEvent()
-            if (event.changes.fastAll { !it.isConsumed }) {
-                with(mouseWheelScrollConfig) {
-                    val scrollAmount = calculateMouseWheelScroll(event, size)
-                    with(scrollingLogicState.value) {
-                        val delta = scrollAmount.toFloat().reverseIfNeeded()
-                        val consumedDelta = scrollableState.dispatchRawDelta(delta)
-                        if (consumedDelta != 0f) {
-                            event.changes.fastForEach { it.consume() }
+private class MouseWheelScrollElement(
+    val scrollingLogicState: State<ScrollingLogic>,
+    val mouseWheelScrollConfig: ScrollConfig
+) : ModifierNodeElement<MouseWheelScrollNode>() {
+    override fun create(): MouseWheelScrollNode {
+        return MouseWheelScrollNode(scrollingLogicState, mouseWheelScrollConfig)
+    }
+
+    override fun update(node: MouseWheelScrollNode): MouseWheelScrollNode = node.also {
+        it.scrollingLogicState = scrollingLogicState
+        it.mouseWheelScrollConfig = mouseWheelScrollConfig
+    }
+
+    override fun hashCode(): Int {
+        var result = scrollingLogicState.hashCode()
+        result = 31 * result + mouseWheelScrollConfig.hashCode()
+        return result
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is MouseWheelScrollElement) return false
+
+        if (scrollingLogicState != other.scrollingLogicState) return false
+        if (mouseWheelScrollConfig != other.mouseWheelScrollConfig) return false
+        return true
+    }
+
+    override fun InspectorInfo.inspectableProperties() = Unit
+}
+
+// TODO(levima) Save the ScrollingLogic value in the ScrollableNode so we won't need a State here.
+private class MouseWheelScrollNode(
+    var scrollingLogicState: State<ScrollingLogic>,
+    var mouseWheelScrollConfig: ScrollConfig
+) : DelegatingNode(), PointerInputModifierNode {
+
+    private val pointerInputNode = SuspendingPointerInputModifierNode {
+        awaitPointerEventScope {
+            while (true) {
+                val event = awaitScrollEvent()
+                if (event.changes.fastAll { !it.isConsumed }) {
+                    with(mouseWheelScrollConfig) {
+                        val scrollAmount = calculateMouseWheelScroll(event, size)
+                        with(scrollingLogicState.value) {
+                            val delta = scrollAmount.toFloat().reverseIfNeeded()
+                            val consumedDelta = scrollableState.dispatchRawDelta(delta)
+                            if (consumedDelta != 0f) {
+                                event.changes.fastForEach { it.consume() }
+                            }
                         }
                     }
                 }
             }
         }
     }
+        // TODO: remove `.node` after aosp/2462416 lands and merge everything into one delegated
+        //  block
+        .also { delegated { it.node } }
+
+    override fun onPointerEvent(
+        pointerEvent: PointerEvent,
+        pass: PointerEventPass,
+        bounds: IntSize
+    ) {
+        pointerInputNode.onPointerEvent(pointerEvent, pass, bounds)
+    }
+
+    override fun onCancelPointerInput() {
+        pointerInputNode.onCancelPointerInput()
+    }
 }
 
 private suspend fun AwaitPointerEventScope.awaitScrollEvent(): PointerEvent {
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 d73e382..43df93c 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
@@ -149,8 +149,8 @@
                         }
                     event.isShiftPressed ->
                         when (event.key) {
-                            MappedKeys.MoveHome -> KeyCommand.SELECT_HOME
-                            MappedKeys.MoveEnd -> KeyCommand.SELECT_END
+                            MappedKeys.MoveHome -> KeyCommand.SELECT_LINE_LEFT
+                            MappedKeys.MoveEnd -> KeyCommand.SELECT_LINE_RIGHT
                             else -> null
                         }
                     event.isAltPressed ->
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Clickable.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Clickable.desktop.kt
index 5fe98ff..1fb5bf4 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Clickable.desktop.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Clickable.desktop.kt
@@ -120,7 +120,6 @@
         }
         Modifier
             .genericClickableWithoutGesture(
-                gestureModifiers = gesture,
                 interactionSource = remember { MutableInteractionSource() },
                 indication = null,
                 indicationScope = rememberCoroutineScope(),
@@ -133,6 +132,7 @@
                 onLongClick = null,
                 onClick = { onClick(EmptyClickContext) }
             )
+            .then(gesture)
     },
     inspectorInfo = debugInspectorInfo {
         name = "clickable"
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.kt
new file mode 100644
index 0000000..b6fd7c1
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextEditFilterTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.ui.text.input.KeyboardType
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@OptIn(ExperimentalFoundationApi::class)
+class TextEditFilterTest {
+
+    @Test
+    fun chainedFilters_areEqual() {
+        val filter1 = TextEditFilter { _, _ ->
+            // Noop
+        }
+        val filter2 = TextEditFilter { _, _ ->
+            // Noop
+        }
+
+        val chain1 = filter1.then(
+            filter2,
+            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+        )
+        val chain2 = filter1.then(
+            filter2,
+            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+        )
+
+        assertThat(chain1).isEqualTo(chain2)
+    }
+
+    @Test
+    fun chainedFilters_areNotEqual_whenKeyboardOptionsDifferent() {
+        val filter1 = TextEditFilter { _, _ ->
+            // Noop
+        }
+        val filter2 = TextEditFilter { _, _ ->
+            // Noop
+        }
+
+        val chain1 = filter1.then(
+            filter2,
+            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email)
+        )
+        val chain2 = filter1.then(
+            filter2,
+            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
+        )
+
+        assertThat(chain1).isNotEqualTo(chain2)
+    }
+
+    @Test
+    fun chainedFilters_areNotEqual_whenFiltersAreDifferent() {
+        val filter1 = TextEditFilter { _, _ ->
+            // Noop
+        }
+        val filter2 = TextEditFilter { _, _ ->
+            // Noop
+        }
+        val filter3 = TextEditFilter { _, _ ->
+            // Noop
+        }
+
+        val chain1 = filter1.then(filter2)
+        val chain2 = filter1.then(filter3)
+
+        assertThat(chain1).isNotEqualTo(chain2)
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelectionTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt
similarity index 75%
rename from compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelectionTest.kt
rename to compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt
index 8b8bbc3..f511c90 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/MutableTextFieldValueWithSelectionTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldBufferWithSelectionTest.kt
@@ -28,11 +28,11 @@
 
 @OptIn(ExperimentalFoundationApi::class)
 @RunWith(JUnit4::class)
-class MutableTextFieldValueWithSelectionTest {
+class TextFieldBufferWithSelectionTest {
 
     @Test
     fun initialSelection() {
-        val state = MutableTextFieldValueWithSelection(TextFieldValue())
+        val state = TextFieldBufferWithSelection(TextFieldCharSequence())
         assertThat(state.selectionInChars).isEqualTo(TextRange(0))
         assertThat(state.hasSelection).isFalse()
     }
@@ -154,52 +154,56 @@
 
     @Test
     fun resetTo_copiesTextAndSelection() {
-        val state = MutableTextFieldValueWithSelection(TextFieldValue("hello", TextRange(2)))
-        val expectedValue = TextFieldValue("world", TextRange(5))
-        state.resetTo(expectedValue)
-        assertThat(state.toTextFieldValue()).isEqualTo(expectedValue)
+        val expectedValue = TextFieldCharSequence("world", TextRange(5))
+        val state = TextFieldBufferWithSelection(
+            value = TextFieldCharSequence("hello", TextRange(2)),
+            sourceValue = expectedValue
+        )
+        state.revertAllChanges()
+        assertThat(state.toTextFieldCharSequence()).isEqualTo(expectedValue)
+        assertThat(state.changes.changeCount).isEqualTo(0)
     }
 
     @Test
     fun testConvertTextFieldValueToAndFromString() {
-        assertThat("".parseAsTextFieldValue()).isEqualTo(TextFieldValue())
-        assertThat("hello".parseAsTextFieldValue()).isEqualTo(TextFieldValue("hello"))
-        assertThat("_hello".parseAsTextFieldValue()).isEqualTo(TextFieldValue("hello"))
-        assertThat("h_ello".parseAsTextFieldValue())
-            .isEqualTo(TextFieldValue("hello", selection = TextRange(1)))
-        assertThat("hello_".parseAsTextFieldValue())
-            .isEqualTo(TextFieldValue("hello", selection = TextRange(5)))
-        assertThat("_hello_".parseAsTextFieldValue())
-            .isEqualTo(TextFieldValue("hello", selection = TextRange(0, 5)))
-        assertThat("he__llo".parseAsTextFieldValue())
-            .isEqualTo(TextFieldValue("hello", selection = TextRange(2)))
-        assertThat("he_l_lo".parseAsTextFieldValue())
-            .isEqualTo(TextFieldValue("hello", selection = TextRange(2, 3)))
+        assertThat("".parseAsTextEditState()).isEqualTo(TextFieldCharSequence())
+        assertThat("hello".parseAsTextEditState()).isEqualTo(TextFieldCharSequence("hello"))
+        assertThat("_hello".parseAsTextEditState()).isEqualTo(TextFieldCharSequence("hello"))
+        assertThat("h_ello".parseAsTextEditState())
+            .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(1)))
+        assertThat("hello_".parseAsTextEditState())
+            .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(5)))
+        assertThat("_hello_".parseAsTextEditState())
+            .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(0, 5)))
+        assertThat("he__llo".parseAsTextEditState())
+            .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(2)))
+        assertThat("he_l_lo".parseAsTextEditState())
+            .isEqualTo(TextFieldCharSequence("hello", selection = TextRange(2, 3)))
         assertFailsWith<ParseException> {
-            "_he_llo_".parseAsTextFieldValue()
+            "_he_llo_".parseAsTextEditState()
         }
 
         listOf("", "_hello", "h_ello", "hello_", "_hello_", "he_ll_o").forEach {
-            val value = it.parseAsTextFieldValue()
+            val value = it.parseAsTextEditState()
             assertThat(value.toParsableString()).isEqualTo(it)
         }
     }
 
     private fun testSelectionAdjustment(
         initial: String,
-        transform: MutableTextFieldValueWithSelection.() -> Unit,
+        transform: TextFieldBufferWithSelection.() -> Unit,
         expected: String
     ) {
-        val state = MutableTextFieldValueWithSelection(initial.parseAsTextFieldValue())
+        val state = TextFieldBufferWithSelection(initial.parseAsTextEditState())
         state.transform()
-        assertThat(state.toTextFieldValue().toParsableString()).isEqualTo(expected)
+        assertThat(state.toTextFieldCharSequence().toParsableString()).isEqualTo(expected)
     }
 
     /**
      * Parses this string into a [TextFieldValue], replacing a single underscore with the cursor, or
      * two underscores with a selection.
      */
-    private fun String.parseAsTextFieldValue(): TextFieldValue {
+    private fun String.parseAsTextEditState(): TextFieldCharSequence {
         var firstMark = -1
         var secondMark = -1
         val source = this
@@ -217,7 +221,7 @@
             }
         }
 
-        return TextFieldValue(
+        return TextFieldCharSequence(
             text = text,
             selection = when {
                 firstMark == -1 -> TextRange.Zero
@@ -227,12 +231,12 @@
         )
     }
 
-    private fun TextFieldValue.toParsableString(): String = buildString {
-        append(text)
+    private fun TextFieldCharSequence.toParsableString(): String = buildString {
+        append(this@toParsableString)
         if (isNotEmpty()) {
-            insert(selection.min, '_')
-            if (!selection.collapsed) {
-                insert(selection.max + 1, '_')
+            insert(selectionInChars.min, '_')
+            if (!selectionInChars.collapsed) {
+                insert(selectionInChars.max + 1, '_')
             }
         }
     }
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt
new file mode 100644
index 0000000..aa490d8
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldCharSequenceTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.input
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.saveable.SaverScope
+import androidx.compose.ui.text.TextRange
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalFoundationApi::class)
+@RunWith(JUnit4::class)
+class TextFieldCharSequenceTest {
+    private val defaultSaverScope = SaverScope { true }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun throws_exception_for_negative_selection() {
+        TextFieldCharSequence(text = "", selection = TextRange(-1))
+    }
+
+    @Test
+    fun aligns_selection_to_the_text_length() {
+        val text = "a"
+        val textFieldValue =
+            TextFieldCharSequence(text = text, selection = TextRange(text.length + 1))
+        assertThat(textFieldValue.selectionInChars.collapsed).isTrue()
+        assertThat(textFieldValue.selectionInChars.max).isEqualTo(textFieldValue.length)
+    }
+
+    @Test
+    fun keep_selection_that_is_less_than_text_length() {
+        val text = "a bc"
+        val selection = TextRange(0, "a".length)
+
+        val textFieldValue = TextFieldCharSequence(text = text, selection = selection)
+
+        assertThat(textFieldValue.toString()).isEqualTo(text)
+        assertThat(textFieldValue.selectionInChars).isEqualTo(selection)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun throws_exception_for_negative_composition() {
+        TextEditState(text = "", composition = TextRange(-1))
+    }
+
+    @Test
+    fun aligns_composition_to_text_length() {
+        val text = "a"
+        val textFieldValue = TextEditState(text = text, composition = TextRange(text.length + 1))
+        assertThat(textFieldValue.compositionInChars?.collapsed).isTrue()
+        assertThat(textFieldValue.compositionInChars?.max).isEqualTo(textFieldValue.length)
+    }
+
+    @Test
+    fun keep_composition_that_is_less_than_text_length() {
+        val text = "a bc"
+        val composition = TextRange(0, "a".length)
+
+        val textFieldValue = TextEditState(text = text, composition = composition)
+
+        assertThat(textFieldValue.toString()).isEqualTo(text)
+        assertThat(textFieldValue.compositionInChars).isEqualTo(composition)
+    }
+
+    @Test
+    fun equals_returns_true_for_same_instance() {
+        val textFieldValue = TextFieldCharSequence(
+            text = "a",
+            selection = TextRange(1),
+            composition = TextRange(2)
+        )
+
+        assertThat(textFieldValue).isEqualTo(textFieldValue)
+    }
+
+    @Test
+    fun equals_returns_true_for_equivalent_object() {
+        val textFieldValue = TextFieldCharSequence(
+            text = "a",
+            selection = TextRange(1),
+            composition = TextRange(2)
+        )
+
+        assertThat(
+            TextFieldCharSequence(
+                textFieldValue,
+                textFieldValue.selectionInChars,
+                textFieldValue.compositionInChars
+            )
+        ).isEqualTo(textFieldValue)
+    }
+
+    @Test
+    fun text_and_selection_parameter_constructor_has_null_composition() {
+        val textFieldValue = TextFieldCharSequence(
+            text = "a",
+            selection = TextRange(1)
+        )
+
+        assertThat(textFieldValue.compositionInChars).isNull()
+    }
+
+    private fun TextEditState(text: String, composition: TextRange) =
+        TextFieldCharSequence(text, selection = TextRange.Zero, composition = composition)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt
index e1ec75d..4325a6a 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateSaverTest.kt
@@ -19,7 +19,6 @@
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.runtime.saveable.SaverScope
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.assertNotNull
 import org.junit.Test
@@ -29,17 +28,15 @@
 
     @Test
     fun savesAndRestoresTextAndSelection() {
-        val state = TextFieldState(
-            TextFieldValue("hello, world", selection = TextRange(0, 5))
-        )
+        val state = TextFieldState("hello, world", initialSelectionInChars = TextRange(0, 5))
 
         val saved = with(TextFieldState.Saver) { TestSaverScope.save(state) }
         assertNotNull(saved)
         val restoredState = TextFieldState.Saver.restore(saved)
 
         assertNotNull(restoredState)
-        assertThat(restoredState.value.text).isEqualTo("hello, world")
-        assertThat(restoredState.value.selection).isEqualTo(TextRange(0, 5))
+        assertThat(restoredState.text.toString()).isEqualTo("hello, world")
+        assertThat(restoredState.text.selectionInChars).isEqualTo(TextRange(0, 5))
     }
 
     private object TestSaverScope : SaverScope {
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt
index 922b052..15de948 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/TextFieldStateTest.kt
@@ -17,15 +17,23 @@
 package androidx.compose.foundation.text2.input
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.assertFailsWith
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
-@OptIn(ExperimentalFoundationApi::class)
+@OptIn(ExperimentalFoundationApi::class, ExperimentalCoroutinesApi::class)
 @RunWith(JUnit4::class)
 class TextFieldStateTest {
 
@@ -33,7 +41,7 @@
 
     @Test
     fun initialValue() {
-        assertThat(state.value.text).isEqualTo("")
+        assertThat(state.text.toString()).isEqualTo("")
     }
 
     @Test
@@ -47,7 +55,7 @@
             }
         }
 
-        assertThat(state.value.text).isEmpty()
+        assertThat(state.text.toString()).isEmpty()
     }
 
     @Test
@@ -66,14 +74,14 @@
             replace(0, 0, "hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
     fun edit_replace_doesNotChangeStateUntilReturn() {
         state.edit {
             replace(0, 0, "hello")
-            assertThat(state.value.text).isEmpty()
+            assertThat(state.text.toString()).isEmpty()
             placeCursorAtEnd()
         }
     }
@@ -86,10 +94,10 @@
             replace(5, 5, " ")
             replace(6, 11, "Compose")
             assertThat(toString()).isEqualTo("hello Compose")
-            assertThat(state.value.text).isEmpty()
+            assertThat(state.text.toString()).isEmpty()
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("hello Compose")
+        assertThat(state.text.toString()).isEqualTo("hello Compose")
     }
 
     @Test
@@ -98,7 +106,7 @@
             replace(0, 0, "hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(5))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
     }
 
     @Test
@@ -107,7 +115,7 @@
             replace(0, 0, "hello")
             placeCursorBeforeCharAt(2)
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(2))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
     }
 
     @Test
@@ -129,7 +137,7 @@
             replace(0, 0, "hello")
             placeCursorBeforeCodepointAt(2)
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(2))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
     }
 
     @Test
@@ -151,7 +159,7 @@
             replace(0, 0, "hello")
             selectAll()
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(0, 5))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
     }
 
     @Test
@@ -160,7 +168,7 @@
             replace(0, 0, "hello")
             selectCharsIn(TextRange(1, 4))
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(1, 4))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
     }
 
     @Test
@@ -188,7 +196,7 @@
             replace(0, 0, "hello")
             selectCodepointsIn(TextRange(1, 4))
         }
-        assertThat(state.value.selection).isEqualTo(TextRange(1, 4))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
     }
 
     @Test
@@ -222,7 +230,7 @@
             assertThat(toString()).isEqualTo("hello world")
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("hello world")
+        assertThat(state.text.toString()).isEqualTo("hello world")
     }
 
     @Test
@@ -231,7 +239,7 @@
             append('c')
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("c")
+        assertThat(state.text.toString()).isEqualTo("c")
     }
 
     @Test
@@ -240,7 +248,7 @@
             append("hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
@@ -249,26 +257,26 @@
             append("hello world", 0, 5)
             placeCursorAtEnd()
         }
-        assertThat(state.value.text).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
     fun setTextAndPlaceCursorAtEnd_works() {
         state.setTextAndPlaceCursorAtEnd("Hello")
-        assertThat(state.value.text).isEqualTo("Hello")
-        assertThat(state.value.selection).isEqualTo(TextRange(5))
+        assertThat(state.text.toString()).isEqualTo("Hello")
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
     }
 
     @Test
     fun setTextAndSelectAll_works() {
         state.setTextAndSelectAll("Hello")
-        assertThat(state.value.text).isEqualTo("Hello")
-        assertThat(state.value.selection).isEqualTo(TextRange(0, 5))
+        assertThat(state.text.toString()).isEqualTo("Hello")
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
     }
 
     @Test
     fun replace_changesAreTracked() {
-        val state = TextFieldState(TextFieldValue("hello world"))
+        val state = TextFieldState("hello world")
         state.edit {
             replace(6, 11, "Compose")
             assertThat(toString()).isEqualTo("hello Compose")
@@ -281,7 +289,7 @@
 
     @Test
     fun appendChar_changesAreTracked() {
-        val state = TextFieldState(TextFieldValue("hello "))
+        val state = TextFieldState("hello ")
         state.edit {
             append('c')
             assertThat(toString()).isEqualTo("hello c")
@@ -294,7 +302,7 @@
 
     @Test
     fun appendCharSequence_changesAreTracked() {
-        val state = TextFieldState(TextFieldValue("hello "))
+        val state = TextFieldState("hello ")
         state.edit {
             append("world")
             assertThat(toString()).isEqualTo("hello world")
@@ -307,7 +315,7 @@
 
     @Test
     fun appendCharSequenceRange_changesAreTracked() {
-        val state = TextFieldState(TextFieldValue("hello "))
+        val state = TextFieldState("hello ")
         state.edit {
             append("hello world", 6, 11)
             assertThat(toString()).isEqualTo("hello world")
@@ -317,4 +325,190 @@
             placeCursorAtEnd()
         }
     }
+
+    @Test
+    fun forEachValues_fires_immediately() = runTestWithSnapshotsThenCancelChildren {
+        val state = TextFieldState("hello", initialSelectionInChars = TextRange(5))
+        val texts = mutableListOf<TextFieldCharSequence>()
+
+        launch(Dispatchers.Unconfined) {
+            state.forEachTextValue { texts += it }
+        }
+
+        assertThat(texts).hasSize(1)
+        assertThat(texts.single()).isSameInstanceAs(state.text)
+        assertThat(texts.single().toString()).isEqualTo("hello")
+        assertThat(texts.single().selectionInChars).isEqualTo(TextRange(5))
+    }
+
+    @Test
+    fun forEachValue_fires_whenTextChanged() = runTestWithSnapshotsThenCancelChildren {
+        val state = TextFieldState(initialSelectionInChars = TextRange(0))
+        val texts = mutableListOf<TextFieldCharSequence>()
+        val initialText = state.text
+
+        launch(Dispatchers.Unconfined) {
+            state.forEachTextValue { texts += it }
+        }
+
+        state.edit {
+            append("hello")
+            placeCursorBeforeCharAt(0)
+        }
+
+        assertThat(texts).hasSize(2)
+        assertThat(texts.last()).isSameInstanceAs(state.text)
+        assertThat(texts.last().toString()).isEqualTo("hello")
+        assertThat(texts.last().selectionInChars).isEqualTo(initialText.selectionInChars)
+    }
+
+    @Test
+    fun forEachValue_fires_whenSelectionChanged() = runTestWithSnapshotsThenCancelChildren {
+        val state = TextFieldState("hello", initialSelectionInChars = TextRange(0))
+        val texts = mutableListOf<TextFieldCharSequence>()
+
+        launch(Dispatchers.Unconfined) {
+            state.forEachTextValue { texts += it }
+        }
+
+        state.edit {
+            placeCursorAtEnd()
+        }
+
+        assertThat(texts).hasSize(2)
+        assertThat(texts.last()).isSameInstanceAs(state.text)
+        assertThat(texts.last().toString()).isEqualTo("hello")
+        assertThat(texts.last().selectionInChars).isEqualTo(TextRange(5))
+    }
+
+    @Test
+    fun forEachValue_firesTwice_whenEditCalledTwice() = runTestWithSnapshotsThenCancelChildren {
+        val state = TextFieldState()
+        val texts = mutableListOf<TextFieldCharSequence>()
+
+        launch(Dispatchers.Unconfined) {
+            state.forEachTextValue { texts += it }
+        }
+
+        state.edit {
+            append("hello")
+            placeCursorAtEnd()
+        }
+
+        state.edit {
+            append(" world")
+            placeCursorAtEnd()
+        }
+
+        assertThat(texts).hasSize(3)
+        assertThat(texts[1].toString()).isEqualTo("hello")
+        assertThat(texts[2]).isSameInstanceAs(state.text)
+        assertThat(texts[2].toString()).isEqualTo("hello world")
+    }
+
+    @Test
+    fun forEachValue_firesOnce_whenMultipleChangesMadeInSingleEdit() =
+        runTestWithSnapshotsThenCancelChildren {
+            val state = TextFieldState()
+            val texts = mutableListOf<TextFieldCharSequence>()
+
+            launch(Dispatchers.Unconfined) {
+                state.forEachTextValue { texts += it }
+            }
+
+            state.edit {
+                append("hello")
+                append(" world")
+                placeCursorAtEnd()
+            }
+
+            assertThat(texts.last()).isSameInstanceAs(state.text)
+            assertThat(texts.last().toString()).isEqualTo("hello world")
+        }
+
+    @Test
+    fun forEachValue_fires_whenChangeMadeInSnapshotIsApplied() =
+        runTestWithSnapshotsThenCancelChildren {
+            val state = TextFieldState()
+            val texts = mutableListOf<TextFieldCharSequence>()
+
+            launch(Dispatchers.Unconfined) {
+                state.forEachTextValue { texts += it }
+            }
+
+            val snapshot = Snapshot.takeMutableSnapshot()
+            snapshot.enter {
+                state.edit {
+                    append("hello")
+                    placeCursorAtEnd()
+                }
+                assertThat(texts.isEmpty())
+            }
+            assertThat(texts.isEmpty())
+
+            snapshot.apply()
+            snapshot.dispose()
+
+            assertThat(texts.last()).isSameInstanceAs(state.text)
+        }
+
+    @Test
+    fun forEachValue_notFired_whenChangeMadeInSnapshotThenDisposed() =
+        runTestWithSnapshotsThenCancelChildren {
+            val state = TextFieldState()
+            val texts = mutableListOf<TextFieldCharSequence>()
+
+            launch(Dispatchers.Unconfined) {
+                state.forEachTextValue { texts += it }
+            }
+
+            val snapshot = Snapshot.takeMutableSnapshot()
+            snapshot.enter {
+                state.edit {
+                    append("hello")
+                    placeCursorAtEnd()
+                }
+            }
+            snapshot.dispose()
+
+            // Only contains initial value.
+            assertThat(texts).hasSize(1)
+            assertThat(texts.single().toString()).isEmpty()
+        }
+
+    @Test
+    fun forEachValue_cancelsPreviousHandler_whenChangeMadeWhileSuspended() =
+        runTestWithSnapshotsThenCancelChildren {
+            val state = TextFieldState()
+            val texts = mutableListOf<TextFieldCharSequence>()
+
+            launch(Dispatchers.Unconfined) {
+                state.forEachTextValue {
+                    texts += it
+                    awaitCancellation()
+                }
+            }
+
+            state.setTextAndPlaceCursorAtEnd("hello")
+            state.setTextAndPlaceCursorAtEnd("world")
+
+            assertThat(texts.map { it.toString() })
+                .containsExactly("", "hello", "world")
+                .inOrder()
+        }
+
+    private fun runTestWithSnapshotsThenCancelChildren(testBody: suspend TestScope.() -> Unit) {
+        val globalWriteObserverHandle = Snapshot.registerGlobalWriteObserver {
+            // This is normally done by the compose runtime.
+            Snapshot.sendApplyNotifications()
+        }
+        try {
+            runTest {
+                testBody()
+                coroutineContext.job.cancelChildren()
+            }
+        } finally {
+            globalWriteObserverHandle.dispose()
+        }
+    }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt
index 18ad7c2..837a3a3 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text2/input/internal/EditProcessorTest.kt
@@ -18,8 +18,8 @@
 
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.text2.input.TextEditFilter
+import androidx.compose.foundation.text2.input.TextFieldCharSequence
 import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.input.TextFieldValue
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -31,7 +31,7 @@
 
     @Test
     fun initializeValue() {
-        val firstValue = TextFieldValue("ABCDE", TextRange.Zero)
+        val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
         val processor = EditProcessor(firstValue)
 
         assertThat(processor.value).isEqualTo(firstValue)
@@ -39,7 +39,7 @@
 
     @Test
     fun apply_commitTextCommand_changesValue() {
-        val firstValue = TextFieldValue("ABCDE", TextRange.Zero)
+        val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
         val processor = EditProcessor(firstValue)
 
         var resetCalled = 0
@@ -48,16 +48,16 @@
         processor.update(CommitTextCommand("X", 1))
         val newState = processor.value
 
-        assertThat(newState.text).isEqualTo("XABCDE")
-        assertThat(newState.selection.min).isEqualTo(1)
-        assertThat(newState.selection.max).isEqualTo(1)
+        assertThat(newState.toString()).isEqualTo("XABCDE")
+        assertThat(newState.selectionInChars.min).isEqualTo(1)
+        assertThat(newState.selectionInChars.max).isEqualTo(1)
         // edit command updates should not trigger reset listeners.
         assertThat(resetCalled).isEqualTo(0)
     }
 
     @Test
     fun apply_setSelectionCommand_changesValue() {
-        val firstValue = TextFieldValue("ABCDE", TextRange.Zero)
+        val firstValue = TextFieldCharSequence("ABCDE", TextRange.Zero)
         val processor = EditProcessor(firstValue)
 
         var resetCalled = 0
@@ -66,9 +66,9 @@
         processor.update(SetSelectionCommand(0, 2))
         val newState = processor.value
 
-        assertThat(newState.text).isEqualTo("ABCDE")
-        assertThat(newState.selection.min).isEqualTo(0)
-        assertThat(newState.selection.max).isEqualTo(2)
+        assertThat(newState.toString()).isEqualTo("ABCDE")
+        assertThat(newState.selectionInChars.min).isEqualTo(0)
+        assertThat(newState.selectionInChars.max).isEqualTo(2)
         // edit command updates should not trigger reset listeners.
         assertThat(resetCalled).isEqualTo(0)
     }
@@ -80,11 +80,11 @@
         processor.addResetListener { _, _ -> resetCalled++ }
 
         val initialBuffer = processor.mBuffer
-        processor.reset(TextFieldValue("qwerty", TextRange.Zero, TextRange.Zero))
+        processor.reset(TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero))
         assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
 
         val updatedBuffer = processor.mBuffer
-        processor.reset(TextFieldValue("qwerty", TextRange.Zero, TextRange.Zero))
+        processor.reset(TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero))
         assertThat(processor.mBuffer).isSameInstanceAs(updatedBuffer)
 
         assertThat(resetCalled).isEqualTo(2)
@@ -96,11 +96,11 @@
         var resetCalled = 0
         processor.addResetListener { _, _ -> resetCalled++ }
 
-        val textFieldValue = TextFieldValue("qwerty", TextRange.Zero, TextRange.Zero)
+        val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
         processor.reset(textFieldValue)
         val initialBuffer = processor.mBuffer
 
-        val newTextFieldValue = TextFieldValue("abc")
+        val newTextFieldValue = TextFieldCharSequence("abc")
         processor.reset(newTextFieldValue)
 
         assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
@@ -113,16 +113,17 @@
         var resetCalled = 0
         processor.addResetListener { _, _ -> resetCalled++ }
 
-        val textFieldValue = TextFieldValue("qwerty", TextRange.Zero, TextRange.Zero)
+        val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange.Zero)
         processor.reset(textFieldValue)
         val initialBuffer = processor.mBuffer
 
-        val newTextFieldValue = textFieldValue.copy(selection = TextRange(1))
+        val newTextFieldValue = TextFieldCharSequence(textFieldValue, selection = TextRange(1))
         processor.reset(newTextFieldValue)
 
         assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
-        assertThat(newTextFieldValue.selection.start).isEqualTo(processor.mBuffer.selectionStart)
-        assertThat(newTextFieldValue.selection.end).isEqualTo(processor.mBuffer.selectionEnd)
+        assertThat(newTextFieldValue.selectionInChars.start)
+            .isEqualTo(processor.mBuffer.selectionStart)
+        assertThat(newTextFieldValue.selectionInChars.end).isEqualTo(processor.mBuffer.selectionEnd)
         assertThat(resetCalled).isEqualTo(2)
     }
 
@@ -132,7 +133,7 @@
         var resetCalled = 0
         processor.addResetListener { _, _ -> resetCalled++ }
 
-        val textFieldValue = TextFieldValue("qwerty", TextRange.Zero, TextRange(1))
+        val textFieldValue = TextFieldCharSequence("qwerty", TextRange.Zero, TextRange(1))
         processor.reset(textFieldValue)
         val initialBuffer = processor.mBuffer
 
@@ -140,7 +141,11 @@
         assertThat(EditingBuffer.NOWHERE).isEqualTo(initialBuffer.compositionStart)
         assertThat(EditingBuffer.NOWHERE).isEqualTo(initialBuffer.compositionEnd)
 
-        val newTextFieldValue = textFieldValue.copy(composition = null)
+        val newTextFieldValue = TextFieldCharSequence(
+            textFieldValue,
+            textFieldValue.selectionInChars,
+            composition = null
+        )
         processor.reset(newTextFieldValue)
 
         assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
@@ -152,7 +157,7 @@
     @Test
     fun testNewState_reversedSelection_setsTheSelection() {
         val initialSelection = TextRange(2, 1)
-        val textFieldValue = TextFieldValue("qwerty", initialSelection, TextRange(1))
+        val textFieldValue = TextFieldCharSequence("qwerty", initialSelection, TextRange(1))
         val processor = EditProcessor(textFieldValue)
         var resetCalled = 0
         processor.addResetListener { _, _ -> resetCalled++ }
@@ -163,7 +168,7 @@
         assertThat(initialSelection.max).isEqualTo(initialBuffer.selectionEnd)
 
         val updatedSelection = TextRange(3, 0)
-        val newTextFieldValue = textFieldValue.copy(selection = updatedSelection)
+        val newTextFieldValue = TextFieldCharSequence(textFieldValue, selection = updatedSelection)
         // set the new selection
         processor.reset(newTextFieldValue)
 
@@ -186,11 +191,16 @@
         )
 
         // change the text
-        val newValue = processor.value.copy(text = "cd")
+        val newValue =
+            TextFieldCharSequence(
+                "cd",
+                processor.value.selectionInChars,
+                processor.value.compositionInChars
+            )
         processor.reset(newValue)
 
-        assertThat(processor.value.text).isEqualTo(newValue.text)
-        assertThat(processor.value.composition).isNull()
+        assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+        assertThat(processor.value.compositionInChars).isNull()
     }
 
     @Test
@@ -205,11 +215,16 @@
         )
 
         // use the same TextFieldValue
-        val newValue = processor.value.copy()
+        val newValue =
+            TextFieldCharSequence(
+                processor.value,
+                processor.value.selectionInChars,
+                processor.value.compositionInChars
+            )
         processor.reset(newValue)
 
-        assertThat(processor.value.text).isEqualTo(newValue.text)
-        assertThat(processor.value.composition).isEqualTo(composition)
+        assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+        assertThat(processor.value.compositionInChars).isEqualTo(composition)
     }
 
     @Test
@@ -223,11 +238,16 @@
         )
 
         // change the composition
-        val newValue = processor.value.copy(composition = TextRange(0, 2))
+        val newValue =
+            TextFieldCharSequence(
+                processor.value,
+                processor.value.selectionInChars,
+                composition = TextRange(0, 2)
+            )
         processor.reset(newValue)
 
-        assertThat(processor.value.text).isEqualTo(newValue.text)
-        assertThat(processor.value.composition).isNull()
+        assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+        assertThat(processor.value.compositionInChars).isNull()
     }
 
     @Test
@@ -241,11 +261,15 @@
         )
 
         // change the composition
-        val newValue = processor.value.copy(composition = TextRange(0, 1))
+        val newValue = TextFieldCharSequence(
+            processor.value,
+            processor.value.selectionInChars,
+            composition = TextRange(0, 1)
+        )
         processor.reset(newValue)
 
-        assertThat(processor.value.text).isEqualTo(newValue.text)
-        assertThat(processor.value.composition).isNull()
+        assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+        assertThat(processor.value.compositionInChars).isNull()
     }
 
     @Test
@@ -264,18 +288,22 @@
 
         // change selection
         val newSelection = TextRange(1)
-        val newValue = processor.value.copy(selection = newSelection)
+        val newValue = TextFieldCharSequence(
+            processor.value,
+            selection = newSelection,
+            composition = processor.value.compositionInChars
+        )
         processor.reset(newValue)
 
-        assertThat(processor.value.text).isEqualTo(newValue.text)
-        assertThat(processor.value.composition).isEqualTo(composition)
-        assertThat(processor.value.selection).isEqualTo(newSelection)
+        assertThat(processor.value.toString()).isEqualTo(newValue.toString())
+        assertThat(processor.value.compositionInChars).isEqualTo(composition)
+        assertThat(processor.value.selectionInChars).isEqualTo(newSelection)
     }
 
     @Test
     fun filterThatDoesNothing_doesNotResetBuffer() {
         val processor = EditProcessor(
-            TextFieldValue(
+            TextFieldCharSequence(
                 "abc",
                 selection = TextRange(3),
                 composition = TextRange(0, 3)
@@ -288,14 +316,14 @@
 
         val value = processor.value
 
-        assertThat(value.text).isEqualTo("abcd")
+        assertThat(value.toString()).isEqualTo("abcd")
         assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
     }
 
     @Test
     fun returningTheEquivalentValueFromFilter_doesNotResetBuffer() {
         val processor = EditProcessor(
-            TextFieldValue(
+            TextFieldCharSequence(
                 "abc",
                 selection = TextRange(3),
                 composition = TextRange(0, 3)
@@ -308,22 +336,22 @@
 
         val value = processor.value
 
-        assertThat(value.text).isEqualTo("abcd")
+        assertThat(value.toString()).isEqualTo("abcd")
         assertThat(processor.mBuffer).isSameInstanceAs(initialBuffer)
     }
 
     @Test
     fun returningOldValueFromFilter_resetsTheBuffer() {
         val processor = EditProcessor(
-            TextFieldValue(
+            TextFieldCharSequence(
                 "abc",
                 selection = TextRange(3),
                 composition = TextRange(0, 3)
             )
         )
 
-        var resetCalledOld: TextFieldValue? = null
-        var resetCalledNew: TextFieldValue? = null
+        var resetCalledOld: TextFieldCharSequence? = null
+        var resetCalledNew: TextFieldCharSequence? = null
         processor.addResetListener { old, new ->
             resetCalledOld = old
             resetCalledNew = new
@@ -331,14 +359,14 @@
 
         val initialBuffer = processor.mBuffer
 
-        processor.update(CommitTextCommand("d", 4)) { old, new -> new.resetTo(old) }
+        processor.update(CommitTextCommand("d", 4)) { _, new -> new.revertAllChanges() }
 
         val value = processor.value
 
-        assertThat(value.text).isEqualTo("abc")
+        assertThat(value.toString()).isEqualTo("abc")
         assertThat(processor.mBuffer).isNotSameInstanceAs(initialBuffer)
-        assertThat(resetCalledOld?.text).isEqualTo("abcd") // what IME applied
-        assertThat(resetCalledNew?.text).isEqualTo("abc") // what is decided by filter
+        assertThat(resetCalledOld?.toString()).isEqualTo("abcd") // what IME applied
+        assertThat(resetCalledNew?.toString()).isEqualTo("abc") // what is decided by filter
     }
 
     private fun EditProcessor.update(
diff --git a/compose/material/material-icons-core/build.gradle b/compose/material/material-icons-core/build.gradle
index 73c4aec..0276b88 100644
--- a/compose/material/material-icons-core/build.gradle
+++ b/compose/material/material-icons-core/build.gradle
@@ -15,103 +15,65 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
 import androidx.compose.material.icons.generator.tasks.IconGenerationTask
 
-
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api("androidx.compose.ui:ui:1.2.1")
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation(libs.kotlinStdlib)
+
+        samples(project(":compose:material:material-icons-core:material-icons-core-samples"))
+    }
+}
+
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                api("androidx.compose.ui:ui:1.2.1")
+                api(project(":compose:ui:ui"))
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
+            androidMain.dependencies {
                 implementation(libs.kotlinStdlib)
             }
         }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:ui:ui"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-            }
-        }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
-            }
-        }
+    }
+    dependencies {
+        samples(project(":compose:material:material-icons-core:material-icons-core-samples"))
     }
 }
 
 IconGenerationTask.registerCoreIconProject(
         project,
         android,
-        true
+        AndroidXComposePlugin.isMultiplatformEnabled(project)
 )
 
 androidx {
diff --git a/compose/material/material-icons-extended/build.gradle b/compose/material/material-icons-extended/build.gradle
index 6e03e7d..4a58d27 100644
--- a/compose/material/material-icons-extended/build.gradle
+++ b/compose/material/material-icons-extended/build.gradle
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
 import androidx.build.RunApiTasks
 import androidx.compose.material.icons.generator.tasks.IconGenerationTask
+import androidx.compose.material.icons.generator.tasks.ExtendedIconGenerationTask
 
 plugins {
     id("AndroidXPlugin")
@@ -25,7 +26,7 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
 IconGenerationTask.registerExtendedIconMainProject(
         project,
@@ -34,64 +35,38 @@
 
 apply from: "shared-dependencies.gradle"
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
-                api(project(":compose:material:material-icons-core"))
-                implementation(libs.kotlinStdlibCommon)
-                implementation(project(":compose:runtime:runtime"))
-            }
-        }
+    if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make an analogous update in the
+         * corresponding block below
+         */
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.kotlinReflect)
+        androidTestImplementation(libs.truth)
 
-        commonTest {
-            dependencies {
-            }
-        }
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation(project(":compose:foundation:foundation-layout"))
+        androidTestImplementation(project(":compose:ui:ui"))
+        androidTestImplementation(project(":test:screenshot:screenshot"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation("androidx.activity:activity-compose:1.3.1")
+        androidTestImplementation("androidx.appcompat:appcompat:1.3.0")
+    }
+}
 
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:foundation:foundation"))
                 implementation(project(":compose:foundation:foundation-layout"))
                 implementation(project(":compose:ui:ui"))
@@ -108,22 +83,6 @@
                 implementation(libs.truth)
             }
         }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
-            }
-        }
     }
 }
 
@@ -145,7 +104,36 @@
 
 }
 
-IconGenerationTask.registerExtendedIconThemeProject(project, android)
+if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    for (themeName in allThemes) {
+        def otherProject = project(":compose:material:material-icons-extended-" + themeName)
+        project.dependencies.add("embedThemesDebug", otherProject)
+        project.dependencies.add("embedThemesRelease", otherProject)
+    }
+    // Compiling all of the icons in this project takes a while,
+    // so when possible, we compile each theme in its own project and merge them here.
+    // Hopefully we can revert this when parallel compilation is supported:
+    // https://youtrack.jetbrains.com/issue/KT-46085
+    android {
+        libraryVariants.all { v ->
+            if (v.name.toLowerCase().contains("debug")) {
+                v.registerPostJavacGeneratedBytecode(configurations.embedThemesDebug)
+            } else {
+                v.registerPostJavacGeneratedBytecode(configurations.embedThemesRelease)
+            }
+            // Manually set up source jar generation
+            ExtendedIconGenerationTask.registerSourceJarOnly(project, v)
+        }
+    }
+} else {
+    // We're not sure how to compile these icons in parallel when multiplatform is enabled
+    IconGenerationTask.registerExtendedIconThemeProject(
+            project,
+            android,
+            AndroidXComposePlugin.isMultiplatformEnabled(project)
+    )
+}
+
 
 androidx {
     name = "Compose Material Icons Extended"
diff --git a/compose/material/material-icons-extended/generate.gradle b/compose/material/material-icons-extended/generate.gradle
index eb45afa..aed94d9 100644
--- a/compose/material/material-icons-extended/generate.gradle
+++ b/compose/material/material-icons-extended/generate.gradle
@@ -25,9 +25,17 @@
 apply plugin: "com.android.library"
 apply plugin: "AndroidXComposePlugin"
 
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 apply from: "${buildscript.sourceFile.parentFile}/shared-dependencies.gradle"
 
-IconGenerationTask.registerExtendedIconThemeProject(project, android)
+if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    // We're not sure how to merge icons jars when multiplatform is enabled
+    IconGenerationTask.registerExtendedIconThemeProject(
+            project,
+            android,
+            AndroidXComposePlugin.isMultiplatformEnabled(project)
+    )
+}
 
 dependencies.attributesSchema {
     attribute(iconExportAttr)
diff --git a/compose/material/material-icons-extended/shared-dependencies.gradle b/compose/material/material-icons-extended/shared-dependencies.gradle
index 2de0ef0..f2cbca1 100644
--- a/compose/material/material-icons-extended/shared-dependencies.gradle
+++ b/compose/material/material-icons-extended/shared-dependencies.gradle
@@ -18,25 +18,36 @@
 // by its specific theme projects (each of which compile a specific theme)
 
 import androidx.build.AndroidXComposePlugin
-import androidx.build.KmpPlatformsKt
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
-
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
+    if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make an analogous update in the
+         * corresponding block below
+         */
+       api(project(":compose:material:material-icons-core"))
+       implementation(libs.kotlinStdlibCommon)
+       implementation(project(":compose:runtime:runtime"))
+    }
 }
 
-kotlin {
-    /*
-     * When updating dependencies, make sure to make an analogous update in the
-     * corresponding block above
-     */
-    sourceSets {
-        commonMain.dependencies {
-            api(project(":compose:material:material-icons-core"))
-            implementation(libs.kotlinStdlibCommon)
-            implementation(project(":compose:runtime:runtime"))
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
+                api(project(":compose:material:material-icons-core"))
+                implementation(libs.kotlinStdlibCommon)
+                implementation(project(":compose:runtime:runtime"))
+            }
         }
     }
 }
diff --git a/compose/material/material-ripple/build.gradle b/compose/material/material-ripple/build.gradle
index 0dd2c95..31a99bb 100644
--- a/compose/material/material-ripple/build.gradle
+++ b/compose/material/material-ripple/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,73 +24,68 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        api("androidx.compose.foundation:foundation:1.2.1")
+        api("androidx.compose.runtime:runtime:1.2.1")
+
+        implementation(libs.kotlinStdlibCommon)
+        implementation("androidx.compose.animation:animation:1.2.1")
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                api("androidx.compose.foundation:foundation:1.2.1")
-                api("androidx.compose.runtime:runtime:1.2.1")
+                api(project(":compose:foundation:foundation"))
+                api(project(":compose:runtime:runtime"))
 
-                implementation("androidx.compose.animation:animation:1.2.1")
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:animation:animation"))
+                implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
-        }
 
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:foundation:foundation"))
-                    api(project(":compose:runtime:runtime"))
-                    implementation(project(":compose:animation:animation"))
-                    implementation(project(":compose:ui:ui-util"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:test-utils"))
 
                 implementation(libs.testRules)
@@ -98,30 +94,6 @@
                 implementation(libs.truth)
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
-            }
-        }
     }
 }
 
@@ -133,7 +105,7 @@
     // Disable strict API mode for MPP builds as it will fail to compile androidAndroidTest
     // sources, as it doesn't understand that they are tests and thinks they should have explicit
     // visibility
-    legacyDisableKotlinStrictApiMode = true
+    legacyDisableKotlinStrictApiMode = AndroidXComposePlugin.isMultiplatformEnabled(project)
 }
 
 android {
diff --git a/compose/material/material/build.gradle b/compose/material/material/build.gradle
index 0c39535..cc48985 100644
--- a/compose/material/material/build.gradle
+++ b/compose/material/material/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
 
 plugins {
@@ -24,59 +24,85 @@
     id("AndroidXPaparazziPlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        api("androidx.compose.animation:animation-core:1.2.1")
+        api(project(":compose:foundation:foundation"))
+        api(project(":compose:material:material-icons-core"))
+        api(project(":compose:material:material-ripple"))
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api("androidx.compose.ui:ui:1.2.1")
+        api("androidx.compose.ui:ui-text:1.2.1")
+
+        implementation(libs.kotlinStdlibCommon)
+        implementation("androidx.compose.animation:animation:1.2.1")
+        implementation("androidx.compose.foundation:foundation-layout:1.2.1")
+        implementation("androidx.compose.ui:ui-util:1.2.1")
+
+        // TODO: remove next 3 dependencies when b/202810604 is fixed
+        implementation("androidx.savedstate:savedstate:1.2.1")
+        implementation("androidx.lifecycle:lifecycle-runtime:2.6.1")
+        implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:material:material:material-samples"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":test:screenshot:screenshot"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.mockitoKotlin)
+        androidTestImplementation(libs.testUiautomator)
+
+        lintPublish project(":compose:material:material-lint")
+
+        samples(project(":compose:material:material:material-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                api("androidx.compose.animation:animation-core:1.2.1")
+                api(project(":compose:animation:animation-core"))
                 api(project(":compose:foundation:foundation"))
                 api(project(":compose:material:material-icons-core"))
                 api(project(":compose:material:material-ripple"))
-                api("androidx.compose.runtime:runtime:1.2.1")
-                api("androidx.compose.ui:ui:1.2.1")
-                api("androidx.compose.ui:ui-text:1.2.1")
+                api(project(":compose:runtime:runtime"))
+                api(project(":compose:ui:ui"))
+                api(project(":compose:ui:ui-text"))
 
-                implementation("androidx.compose.animation:animation:1.2.1")
-                implementation("androidx.compose.foundation:foundation-layout:1.2.1")
-                implementation("androidx.compose.ui:ui-util:1.2.1")
+                implementation(project(":compose:animation:animation"))
+                implementation(project(":compose:foundation:foundation-layout"))
+                implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:animation:animation-core"))
-                    api(project(":compose:runtime:runtime"))
-                    api(project(":compose:ui:ui"))
-                    api(project(":compose:ui:ui-text"))
-                    implementation(project(":compose:animation:animation"))
-                    implementation(project(":compose:foundation:foundation-layout"))
-                    implementation(project(":compose:ui:ui-util"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
 
                 // TODO: remove next 3 dependencies when b/202810604 is fixed
@@ -84,29 +110,23 @@
                 implementation("androidx.lifecycle:lifecycle-runtime:2.6.1")
                 implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:material:material:material-samples"))
                 implementation(project(":compose:test-utils"))
                 implementation(project(":test:screenshot:screenshot"))
@@ -120,40 +140,18 @@
                 implementation(libs.mockitoKotlin)
                 implementation(libs.testUiautomator)
             }
-        }
 
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
+            desktopTest.dependencies {
+                implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                    implementation(libs.truth)
-                    implementation(libs.junit)
-                    implementation(libs.skikoCurrentOs)
-                }
+                implementation(libs.junit)
+                implementation(libs.skikoCurrentOs)
             }
         }
     }
-}
-
-dependencies {
-    lintPublish project(":compose:material:material-lint")
+    dependencies {
+        samples(project(":compose:material:material:material-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/tasks/IconGenerationTask.kt b/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/tasks/IconGenerationTask.kt
index d705315..2fe5d63 100644
--- a/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/tasks/IconGenerationTask.kt
+++ b/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/tasks/IconGenerationTask.kt
@@ -157,10 +157,15 @@
         @JvmStatic
         fun registerExtendedIconThemeProject(
             project: Project,
-            libraryExtension: LibraryExtension
+            libraryExtension: LibraryExtension,
+            isMpp: Boolean
         ) {
-            libraryExtension.libraryVariants.all { variant ->
-                ExtendedIconGenerationTask.register(project, variant)
+            if (isMpp) {
+                ExtendedIconGenerationTask.register(project, null)
+            } else {
+                libraryExtension.libraryVariants.all { variant ->
+                    ExtendedIconGenerationTask.register(project, variant)
+                }
             }
 
             // b/175401659 - disable lint as it takes a long time, and most errors should
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
index 50e5533..fbf5030 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
@@ -18,20 +18,20 @@
 
 import android.os.Build
 import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.interaction.DragInteraction
 import androidx.compose.foundation.Indication
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.HoverInteraction
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.PressInteraction
-import androidx.compose.foundation.indication
-import androidx.compose.foundation.interaction.FocusInteraction
-import androidx.compose.foundation.interaction.HoverInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.ripple.LocalRippleTheme
@@ -44,7 +44,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
-import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -62,7 +61,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
-import androidx.test.screenshot.AndroidXScreenshotTestRule
 import com.google.common.truth.Truth
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -76,15 +74,22 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@SdkSuppress(
+    // Below P the press ripple is split into two layers with half alpha, and we multiply the alpha
+    // first so each layer will have the expected alpha to ensure that the minimum contrast in
+    // areas where the ripples don't overlap is still correct - as a result the colors aren't
+    // exactly what we expect here so we can't really reliably assert
+    minSdkVersion = Build.VERSION_CODES.P,
+    // On S and above, the press ripple is patterned and has inconsistent behaviour in terms of
+    // alpha, so it doesn't behave according to our expectations - we can't explicitly assert on the
+    // color.
+    maxSdkVersion = Build.VERSION_CODES.R
+)
 class MaterialRippleThemeTest {
 
     @get:Rule
     val rule = createComposeRule()
 
-    @get:Rule
-    val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL)
-
     @Test
     fun bounded_lightTheme_highLuminance_pressed() {
         val interactionSource = MutableInteractionSource()
@@ -102,7 +107,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_bounded_light_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
     }
@@ -124,7 +128,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_bounded_light_highluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -146,7 +149,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_bounded_light_highluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
     }
@@ -168,7 +170,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_bounded_light_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
     }
@@ -190,7 +191,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_bounded_light_lowluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -212,7 +212,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_bounded_light_lowluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.04f)
         )
     }
@@ -234,7 +233,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_bounded_light_lowluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -256,7 +254,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_bounded_light_lowluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -278,7 +275,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_bounded_dark_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.10f)
         )
     }
@@ -300,7 +296,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_bounded_dark_highluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.04f)
         )
     }
@@ -322,7 +317,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_bounded_dark_highluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -344,7 +338,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_bounded_dark_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -366,7 +359,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_bounded_dark_lowluminance_pressed",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.10f)
         )
@@ -389,7 +381,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_bounded_dark_lowluminance_hovered",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.04f)
         )
@@ -412,7 +403,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_bounded_dark_lowluminance_focused",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.12f)
         )
@@ -435,7 +425,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_bounded_dark_lowluminance_dragged",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.08f)
         )
@@ -458,7 +447,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_unbounded_light_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
     }
@@ -480,7 +468,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_unbounded_light_highluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -502,7 +489,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_unbounded_light_highluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
     }
@@ -524,7 +510,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_unbounded_light_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
     }
@@ -546,7 +531,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_unbounded_light_lowluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -568,7 +552,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_unbounded_light_lowluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.04f)
         )
     }
@@ -590,7 +573,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_unbounded_light_lowluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -612,7 +594,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_unbounded_light_lowluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -634,7 +615,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_unbounded_dark_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.10f)
         )
     }
@@ -656,7 +636,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_unbounded_dark_highluminance_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.04f)
         )
     }
@@ -678,7 +657,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_unbounded_dark_highluminance_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -700,7 +678,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_unbounded_dark_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -722,7 +699,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_unbounded_dark_lowluminance_pressed",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.10f)
         )
@@ -745,7 +721,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_unbounded_dark_lowluminance_hovered",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.04f)
         )
@@ -768,7 +743,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_unbounded_dark_lowluminance_focused",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.12f)
         )
@@ -791,7 +765,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_unbounded_dark_lowluminance_dragged",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.08f)
         )
@@ -843,7 +816,6 @@
             scope!!,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_customtheme_pressed",
             expectedColor
         )
     }
@@ -894,7 +866,6 @@
             scope!!,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_customtheme_hovered",
             expectedColor
         )
     }
@@ -945,7 +916,6 @@
             scope!!,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_customtheme_focused",
             expectedColor
         )
     }
@@ -995,7 +965,6 @@
             scope!!,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_customtheme_dragged",
             expectedColor
         )
     }
@@ -1144,12 +1113,10 @@
     }
 
     /**
-     * Asserts that the ripple matches the screenshot with identifier [goldenIdentifier], and
-     * that the resultant color of the ripple on screen matches [expectedCenterPixelColor].
+     * Asserts that the resultant color of the ripple on screen matches [expectedCenterPixelColor].
      *
      * @param interactionSource the [MutableInteractionSource] driving the ripple
      * @param interaction the [Interaction] to assert for
-     * @param goldenIdentifier the identifier for the corresponding screenshot
      * @param expectedCenterPixelColor the expected color for the pixel at the center of the
      * [RippleBoxWithBackground]
      */
@@ -1157,7 +1124,6 @@
         scope: CoroutineScope,
         interactionSource: MutableInteractionSource,
         interaction: Interaction,
-        goldenIdentifier: String,
         expectedCenterPixelColor: Color
     ) {
         // Pause the clock if we are drawing a state layer
@@ -1182,14 +1148,9 @@
             rule.mainClock.advanceTimeBy(milliseconds = 300)
         }
 
-        // Capture and compare screenshots
-        val screenshot = rule.onNodeWithTag(Tag)
-            .captureToImage()
-
-        screenshot.assertAgainstGolden(screenshotRule, goldenIdentifier)
-
         // Compare expected and actual pixel color
-        val centerPixel = screenshot
+        val centerPixel = rule.onNodeWithTag(Tag)
+            .captureToImage()
             .asAndroidBitmap()
             .run {
                 getPixel(width / 2, height / 2)
diff --git a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
index 2ff7188..4da69f2 100644
--- a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
+++ b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
@@ -69,7 +69,10 @@
  * @param expanded Whether the menu is currently open and visible to the user
  * @param onDismissRequest Called when the user requests to dismiss the menu, such as by
  * tapping outside the menu's bounds
+ * @param focusable Whether the dropdown can capture focus
+ * @param modifier Modifier for the menu
  * @param offset [DpOffset] to be added to the position of the menu
+ * @param content content lambda
  */
 @Suppress("ModifierParameter")
 @Composable
diff --git a/compose/material3/material3-adaptive/api/current.txt b/compose/material3/material3-adaptive/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/compose/material3/material3-adaptive/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/compose/material3/material3-adaptive/api/public_plus_experimental_current.txt b/compose/material3/material3-adaptive/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/compose/material3/material3-adaptive/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/compose/material3/material3-adaptive/api/res-current.txt b/compose/material3/material3-adaptive/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/material3-adaptive/api/res-current.txt
diff --git a/compose/material3/material3-adaptive/api/restricted_current.txt b/compose/material3/material3-adaptive/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/compose/material3/material3-adaptive/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/compose/material3/material3-adaptive/build.gradle b/compose/material3/material3-adaptive/build.gradle
new file mode 100644
index 0000000..43c428c
--- /dev/null
+++ b/compose/material3/material3-adaptive/build.gradle
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.AndroidXComposePlugin
+import androidx.build.LibraryType
+import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXComposePlugin")
+}
+
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
+
+dependencies {
+
+
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+
+        api("androidx.annotation:annotation:1.1.0")
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
+                implementation(libs.kotlinStdlibCommon)
+            }
+
+            androidMain.dependencies {
+                api("androidx.annotation:annotation:1.1.0")
+            }
+
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
+            }
+        }
+    }
+}
+
+android {
+    namespace "androidx.compose.material3.adaptive"
+}
+
+androidx {
+    name = "Material Adaptive"
+    mavenVersion = LibraryVersions.COMPOSE_MATERIAL3_ADAPTIVE
+    type = LibraryType.PUBLISHED_LIBRARY
+    publish = Publish.SNAPSHOT_ONLY
+    inceptionYear = "2023"
+    description = "Compose Material Design Adaptive Library"
+}
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/androidx-compose-material3-adaptive-documentation.md b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/androidx-compose-material3-adaptive-documentation.md
new file mode 100644
index 0000000..a2f8852
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/androidx-compose-material3-adaptive-documentation.md
@@ -0,0 +1,6 @@
+# Module root
+
+Compose Material Adaptive
+
+# Package androidx.compose.material3.adaptive
+
diff --git a/compose/material3/material3-window-size-class/api/1.1.0-beta03.txt b/compose/material3/material3-window-size-class/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..cc66d9f
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/1.1.0-beta03.txt
@@ -0,0 +1,44 @@
+// Signature format: 4.0
+package androidx.compose.material3.windowsizeclass {
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+  @androidx.compose.runtime.Immutable public final class WindowSizeClass {
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
+    field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+}
+
diff --git a/compose/material3/material3-window-size-class/api/current.ignore b/compose/material3/material3-window-size-class/api/current.ignore
deleted file mode 100644
index bb4a3ed..0000000
--- a/compose/material3/material3-window-size-class/api/current.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.compose.material3.windowsizeclass.AndroidWindowSizeClass_androidKt:
-    Removed class androidx.compose.material3.windowsizeclass.AndroidWindowSizeClass_androidKt
-RemovedClass: androidx.compose.material3.windowsizeclass.TestOnly_jvmKt:
-    Removed class androidx.compose.material3.windowsizeclass.TestOnly_jvmKt
diff --git a/compose/material3/material3-window-size-class/api/public_plus_experimental_1.1.0-beta03.txt b/compose/material3/material3-window-size-class/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..88ceafc
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,52 @@
+// Signature format: 4.0
+package androidx.compose.material3.windowsizeclass {
+
+  public final class AndroidWindowSizeClass_androidKt {
+    method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @androidx.compose.runtime.Composable public static androidx.compose.material3.windowsizeclass.WindowSizeClass calculateWindowSizeClass(android.app.Activity activity);
+  }
+
+  @kotlin.RequiresOptIn(message="This material3-window-size-class API is experimental and is likely to change or to " + "be removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3WindowSizeClassApi {
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+  @androidx.compose.runtime.Immutable public final class WindowSizeClass {
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
+    field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+    method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @org.jetbrains.annotations.TestOnly public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size);
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+}
+
diff --git a/compose/material3/material3-window-size-class/api/res-1.1.0-beta03.txt b/compose/material3/material3-window-size-class/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/res-1.1.0-beta03.txt
diff --git a/compose/material3/material3-window-size-class/api/restricted_1.1.0-beta03.txt b/compose/material3/material3-window-size-class/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..cc66d9f
--- /dev/null
+++ b/compose/material3/material3-window-size-class/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,44 @@
+// Signature format: 4.0
+package androidx.compose.material3.windowsizeclass {
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+  @androidx.compose.runtime.Immutable public final class WindowSizeClass {
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
+    field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
+    field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
+  }
+
+}
+
diff --git a/compose/material3/material3-window-size-class/api/restricted_current.ignore b/compose/material3/material3-window-size-class/api/restricted_current.ignore
deleted file mode 100644
index bb4a3ed..0000000
--- a/compose/material3/material3-window-size-class/api/restricted_current.ignore
+++ /dev/null
@@ -1,5 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.compose.material3.windowsizeclass.AndroidWindowSizeClass_androidKt:
-    Removed class androidx.compose.material3.windowsizeclass.AndroidWindowSizeClass_androidKt
-RemovedClass: androidx.compose.material3.windowsizeclass.TestOnly_jvmKt:
-    Removed class androidx.compose.material3.windowsizeclass.TestOnly_jvmKt
diff --git a/compose/material3/material3-window-size-class/build.gradle b/compose/material3/material3-window-size-class/build.gradle
index 94c9a9c..9eb3383 100644
--- a/compose/material3/material3-window-size-class/build.gradle
+++ b/compose/material3/material3-window-size-class/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
 import androidx.build.AndroidXComposePlugin
-import androidx.build.KmpPlatformsKt
 import androidx.build.LibraryType
+import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -25,75 +25,69 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api("androidx.compose.ui:ui:1.2.1")
+        api("androidx.compose.ui:ui-unit:1.2.1")
+        implementation("androidx.window:window:1.0.0")
+
+        testImplementation(libs.kotlinTest)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+
+        samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    kotlin {
+        android()
+        jvm("desktop")
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                api("androidx.compose.runtime:runtime:1.2.1")
-                api("androidx.compose.ui:ui:1.2.1")
-                api("androidx.compose.ui:ui-unit:1.2.1")
+                api(project(":compose:runtime:runtime"))
+                api(project(":compose:ui:ui"))
+                api(project(":compose:ui:ui-unit"))
             }
-        }
 
-        commonTest {
-            dependencies {
-
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
+            jvmMain.dependencies {
                 implementation(libs.kotlinStdlib)
             }
-        }
 
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    // Because dependencies are pinned in the android/common code.
-                    api(project(":compose:runtime:runtime"))
-                    api(project(":compose:ui:ui"))
-                    api(project(":compose:ui:ui-unit"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 implementation("androidx.window:window:1.0.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
+            androidMain.dependsOn(jvmMain)
+            desktopMain.dependsOn(jvmMain)
 
-                }
+            androidTest.dependencies {
+                implementation(libs.kotlinTest)
+                implementation(libs.truth)
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:test-utils"))
                 implementation(project(":compose:foundation:foundation"))
                 implementation(libs.testRules)
@@ -102,25 +96,9 @@
                 implementation(libs.truth)
             }
         }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.kotlinTest)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-
-                }
-            }
-        }
+    }
+    dependencies {
+        samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
     }
 }
 
diff --git a/compose/material3/material3/api/1.1.0-beta03.txt b/compose/material3/material3/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..a0df8a5
--- /dev/null
+++ b/compose/material3/material3/api/1.1.0-beta03.txt
@@ -0,0 +1,881 @@
+// Signature format: 4.0
+package androidx.compose.material3 {
+
+  public final class AlertDialogDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getIconContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public long getTextContentColor();
+    method @androidx.compose.runtime.Composable public long getTitleContentColor();
+    method public float getTonalElevation();
+    property public final float TonalElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long iconContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final long textContentColor;
+    property @androidx.compose.runtime.Composable public final long titleContentColor;
+    field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
+  }
+
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
+  public final class AndroidMenu_androidKt {
+    method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean enabled, optional androidx.compose.material3.MenuItemColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class AppBarKt {
+    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);
+    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);
+  }
+
+  public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+  }
+
+  public final class BottomAppBarDefaults {
+    method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getContainerElevation();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    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 @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;
+    field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ButtonColors {
+  }
+
+  public final class ButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors buttonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation buttonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors elevatedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
+    method public float getIconSize();
+    method public float getIconSpacing();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke getOutlinedButtonBorder();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonWithIconContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+    property public final float IconSize;
+    property public final float IconSpacing;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonWithIconContentPadding;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledTonalShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.BorderStroke outlinedButtonBorder;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape textShape;
+    field public static final androidx.compose.material3.ButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class ButtonElevation {
+  }
+
+  public final class ButtonKt {
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardColors {
+  }
+
+  public final class CardDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors cardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation cardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors elevatedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation elevatedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedCardBorder(optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors outlinedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation outlinedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.CardDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardElevation {
+  }
+
+  public final class CardKt {
+    method @androidx.compose.runtime.Composable public static void Card(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CheckboxColors {
+  }
+
+  public final class CheckboxDefaults {
+    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);
+    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, 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);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
+  }
+
+  public final class ChipKt {
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public final class ColorScheme {
+    ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+    method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public long getBackground();
+    method public long getError();
+    method public long getErrorContainer();
+    method public long getInverseOnSurface();
+    method public long getInversePrimary();
+    method public long getInverseSurface();
+    method public long getOnBackground();
+    method public long getOnError();
+    method public long getOnErrorContainer();
+    method public long getOnPrimary();
+    method public long getOnPrimaryContainer();
+    method public long getOnSecondary();
+    method public long getOnSecondaryContainer();
+    method public long getOnSurface();
+    method public long getOnSurfaceVariant();
+    method public long getOnTertiary();
+    method public long getOnTertiaryContainer();
+    method public long getOutline();
+    method public long getOutlineVariant();
+    method public long getPrimary();
+    method public long getPrimaryContainer();
+    method public long getScrim();
+    method public long getSecondary();
+    method public long getSecondaryContainer();
+    method public long getSurface();
+    method public long getSurfaceTint();
+    method public long getSurfaceVariant();
+    method public long getTertiary();
+    method public long getTertiaryContainer();
+    property public final long background;
+    property public final long error;
+    property public final long errorContainer;
+    property public final long inverseOnSurface;
+    property public final long inversePrimary;
+    property public final long inverseSurface;
+    property public final long onBackground;
+    property public final long onError;
+    property public final long onErrorContainer;
+    property public final long onPrimary;
+    property public final long onPrimaryContainer;
+    property public final long onSecondary;
+    property public final long onSecondaryContainer;
+    property public final long onSurface;
+    property public final long onSurfaceVariant;
+    property public final long onTertiary;
+    property public final long onTertiaryContainer;
+    property public final long outline;
+    property public final long outlineVariant;
+    property public final long primary;
+    property public final long primaryContainer;
+    property public final long scrim;
+    property public final long secondary;
+    property public final long secondaryContainer;
+    property public final long surface;
+    property public final long surfaceTint;
+    property public final long surfaceVariant;
+    property public final long tertiary;
+    property public final long tertiaryContainer;
+  }
+
+  public final class ColorSchemeKt {
+    method public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
+    method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+  }
+
+  public final class ContentColorKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> getLocalContentColor();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
+  }
+
+  public final class DividerDefaults {
+    method @androidx.compose.runtime.Composable public long getColor();
+    method public float getThickness();
+    property public final float Thickness;
+    property @androidx.compose.runtime.Composable public final long color;
+    field public static final androidx.compose.material3.DividerDefaults INSTANCE;
+  }
+
+  public final class DividerKt {
+    method @androidx.compose.runtime.Composable public static void Divider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+  }
+
+  public final class DrawerDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getDismissibleDrawerElevation();
+    method public float getMaximumDrawerWidth();
+    method public float getModalDrawerElevation();
+    method public float getPermanentDrawerElevation();
+    method @androidx.compose.runtime.Composable public long getScrimColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float DismissibleDrawerElevation;
+    property public final float MaximumDrawerWidth;
+    property public final float ModalDrawerElevation;
+    property public final float PermanentDrawerElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long scrimColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.DrawerDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class DrawerState {
+    ctor public DrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+    method public suspend Object? animateTo(androidx.compose.material3.DrawerValue targetValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.DrawerValue getCurrentValue();
+    method public androidx.compose.runtime.State<java.lang.Float> getOffset();
+    method public androidx.compose.material3.DrawerValue getTargetValue();
+    method public boolean isAnimationRunning();
+    method public boolean isClosed();
+    method public boolean isOpen();
+    method public suspend Object? open(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.DrawerValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final androidx.compose.material3.DrawerValue currentValue;
+    property public final boolean isAnimationRunning;
+    property public final boolean isClosed;
+    property public final boolean isOpen;
+    property public final androidx.compose.runtime.State<java.lang.Float> offset;
+    property public final androidx.compose.material3.DrawerValue targetValue;
+    field public static final androidx.compose.material3.DrawerState.Companion Companion;
+  }
+
+  public static final class DrawerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DrawerState,androidx.compose.material3.DrawerValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public enum DrawerValue {
+    method public static androidx.compose.material3.DrawerValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.DrawerValue[] values();
+    enum_constant public static final androidx.compose.material3.DrawerValue Closed;
+    enum_constant public static final androidx.compose.material3.DrawerValue Open;
+  }
+
+  public final class DynamicTonalPaletteKt {
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicDarkColorScheme(android.content.Context context);
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicLightColorScheme(android.content.Context context);
+  }
+
+  @kotlin.jvm.JvmInline public final value class FabPosition {
+    field public static final androidx.compose.material3.FabPosition.Companion Companion;
+  }
+
+  public static final class FabPosition.Companion {
+    method public int getCenter();
+    method public int getEnd();
+    property public final int Center;
+    property public final int End;
+  }
+
+  public final class FloatingActionButtonDefaults {
+    method public androidx.compose.material3.FloatingActionButtonElevation bottomAppBarFabElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation elevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExtendedFabShape();
+    method public float getLargeIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getLargeShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getSmallShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation loweredElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    property public final float LargeIconSize;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape extendedFabShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape largeShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape smallShape;
+    field public static final androidx.compose.material3.FloatingActionButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public class FloatingActionButtonElevation {
+  }
+
+  public final class FloatingActionButtonKt {
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean expanded, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void LargeFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void SmallFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconButtonColors {
+  }
+
+  public final class IconButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    field public static final androidx.compose.material3.IconButtonDefaults INSTANCE;
+  }
+
+  public final class IconButtonKt {
+    method @androidx.compose.runtime.Composable public static void FilledIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(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.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class IconKt {
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconToggleButtonColors {
+  }
+
+  public final class InteractiveComponentSizeKt {
+    method public static androidx.compose.ui.Modifier minimumInteractiveComponentSize(androidx.compose.ui.Modifier);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ListItemColors {
+  }
+
+  public final class ListItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ListItemColors colors(optional long containerColor, optional long headlineColor, optional long leadingIconColor, optional long overlineColor, optional long supportingColor, optional long trailingIconColor, optional long disabledHeadlineColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContainerColor();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContentColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long containerColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long contentColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.ListItemDefaults INSTANCE;
+  }
+
+  public final class ListItemKt {
+    method @androidx.compose.runtime.Composable public static void ListItem(kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional androidx.compose.material3.ListItemColors colors, optional float tonalElevation, optional float shadowElevation);
+  }
+
+  public final class MaterialTheme {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
+    field public static final androidx.compose.material3.MaterialTheme INSTANCE;
+  }
+
+  public final class MaterialThemeKt {
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class MenuDefaults {
+    method public androidx.compose.foundation.layout.PaddingValues getDropdownMenuItemContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.MenuItemColors itemColors(optional long textColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledTextColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    property public final androidx.compose.foundation.layout.PaddingValues DropdownMenuItemContentPadding;
+    field public static final androidx.compose.material3.MenuDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class MenuItemColors {
+  }
+
+  public final class NavigationBarDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationBarItemColors {
+  }
+
+  public final class NavigationBarItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationBarItemDefaults INSTANCE;
+  }
+
+  public final class NavigationBarKt {
+    method @androidx.compose.runtime.Composable public static void NavigationBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, 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 NavigationBarItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationBarItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public interface NavigationDrawerItemColors {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> badgeColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean selected);
+  }
+
+  public final class NavigationDrawerItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationDrawerItemColors colors(optional long selectedContainerColor, optional long unselectedContainerColor, optional long selectedIconColor, optional long unselectedIconColor, optional long selectedTextColor, optional long unselectedTextColor, optional long selectedBadgeColor, optional long unselectedBadgeColor);
+    method public androidx.compose.foundation.layout.PaddingValues getItemPadding();
+    property public final androidx.compose.foundation.layout.PaddingValues ItemPadding;
+    field public static final androidx.compose.material3.NavigationDrawerItemDefaults INSTANCE;
+  }
+
+  public final class NavigationDrawerKt {
+    method @androidx.compose.runtime.Composable public static void DismissibleDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DismissibleNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(kotlin.jvm.functions.Function0<kotlin.Unit> label, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.NavigationDrawerItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void PermanentDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void PermanentNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static androidx.compose.material3.DrawerState rememberDrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public final class NavigationRailDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property @androidx.compose.runtime.Composable public final long ContainerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationRailDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationRailItemColors {
+  }
+
+  public final class NavigationRailItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationRailItemDefaults INSTANCE;
+  }
+
+  public final class NavigationRailKt {
+    method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationRailItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Immutable public final class OutlinedTextFieldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method public float getFocusedBorderThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public float getUnfocusedBorderThickness();
+    property public final float FocusedBorderThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final float UnfocusedBorderThickness;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.OutlinedTextFieldDefaults INSTANCE;
+  }
+
+  public final class OutlinedTextFieldKt {
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  public final class ProgressIndicatorDefaults {
+    method @androidx.compose.runtime.Composable public long getCircularColor();
+    method public int getCircularDeterminateStrokeCap();
+    method public int getCircularIndeterminateStrokeCap();
+    method public float getCircularStrokeWidth();
+    method @androidx.compose.runtime.Composable public long getCircularTrackColor();
+    method @androidx.compose.runtime.Composable public long getLinearColor();
+    method public int getLinearStrokeCap();
+    method @androidx.compose.runtime.Composable public long getLinearTrackColor();
+    method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getProgressAnimationSpec();
+    property public final int CircularDeterminateStrokeCap;
+    property public final int CircularIndeterminateStrokeCap;
+    property public final float CircularStrokeWidth;
+    property public final int LinearStrokeCap;
+    property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> ProgressAnimationSpec;
+    property @androidx.compose.runtime.Composable public final long circularColor;
+    property @androidx.compose.runtime.Composable public final long circularTrackColor;
+    property @androidx.compose.runtime.Composable public final long linearColor;
+    property @androidx.compose.runtime.Composable public final long linearTrackColor;
+    field public static final androidx.compose.material3.ProgressIndicatorDefaults INSTANCE;
+  }
+
+  public final class ProgressIndicatorKt {
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+  }
+
+  @androidx.compose.runtime.Immutable public final class RadioButtonColors {
+  }
+
+  public final class RadioButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.RadioButtonColors colors(optional long selectedColor, optional long unselectedColor, optional long disabledSelectedColor, optional long disabledUnselectedColor);
+    field public static final androidx.compose.material3.RadioButtonDefaults INSTANCE;
+  }
+
+  public final class RadioButtonKt {
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.RadioButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class ScaffoldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+    field public static final androidx.compose.material3.ScaffoldDefaults INSTANCE;
+  }
+
+  public final class ScaffoldKt {
+    method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.WindowInsets contentWindowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+  }
+
+  public final class ShapeDefaults {
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Small;
+    field public static final androidx.compose.material3.ShapeDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+  }
+
+  @androidx.compose.runtime.Immutable public final class SliderColors {
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderDefaults {
+    method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
+    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
+    field public static final androidx.compose.material3.SliderDefaults INSTANCE;
+  }
+
+  public final class SliderKt {
+    method @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderPositions {
+    ctor public SliderPositions(optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> initialActiveRange, optional float[] initialTickFractions);
+    method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getActiveRange();
+    method public float[] getTickFractions();
+    property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> activeRange;
+    property public final float[] tickFractions;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarData {
+    method public void dismiss();
+    method public androidx.compose.material3.SnackbarVisuals getVisuals();
+    method public void performAction();
+    property public abstract androidx.compose.material3.SnackbarVisuals visuals;
+  }
+
+  public final class SnackbarDefaults {
+    method @androidx.compose.runtime.Composable public long getActionColor();
+    method @androidx.compose.runtime.Composable public long getActionContentColor();
+    method @androidx.compose.runtime.Composable public long getColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method @androidx.compose.runtime.Composable public long getDismissActionContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property @androidx.compose.runtime.Composable public final long actionColor;
+    property @androidx.compose.runtime.Composable public final long actionContentColor;
+    property @androidx.compose.runtime.Composable public final long color;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    property @androidx.compose.runtime.Composable public final long dismissActionContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SnackbarDefaults INSTANCE;
+  }
+
+  public enum SnackbarDuration {
+    method public static androidx.compose.material3.SnackbarDuration valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarDuration[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Indefinite;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Long;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Short;
+  }
+
+  public final class SnackbarHostKt {
+    method @androidx.compose.runtime.Composable public static void SnackbarHost(androidx.compose.material3.SnackbarHostState hostState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarData,kotlin.Unit> snackbar);
+  }
+
+  @androidx.compose.runtime.Stable public final class SnackbarHostState {
+    ctor public SnackbarHostState();
+    method public androidx.compose.material3.SnackbarData? getCurrentSnackbarData();
+    method public suspend Object? showSnackbar(String message, optional String? actionLabel, optional boolean withDismissAction, optional androidx.compose.material3.SnackbarDuration duration, optional kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    method public suspend Object? showSnackbar(androidx.compose.material3.SnackbarVisuals visuals, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    property public final androidx.compose.material3.SnackbarData? currentSnackbarData;
+  }
+
+  public final class SnackbarKt {
+    method @androidx.compose.runtime.Composable public static void Snackbar(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissAction, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionContentColor, optional long dismissActionContentColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Snackbar(androidx.compose.material3.SnackbarData snackbarData, optional androidx.compose.ui.Modifier modifier, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionColor, optional long actionContentColor, optional long dismissActionContentColor);
+  }
+
+  public enum SnackbarResult {
+    method public static androidx.compose.material3.SnackbarResult valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarResult[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarResult ActionPerformed;
+    enum_constant public static final androidx.compose.material3.SnackbarResult Dismissed;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarVisuals {
+    method public String? getActionLabel();
+    method public androidx.compose.material3.SnackbarDuration getDuration();
+    method public String getMessage();
+    method public boolean getWithDismissAction();
+    property public abstract String? actionLabel;
+    property public abstract androidx.compose.material3.SnackbarDuration duration;
+    property public abstract String message;
+    property public abstract boolean withDismissAction;
+  }
+
+  public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+  }
+
+  public final class SurfaceKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(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.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
+  }
+
+  @androidx.compose.runtime.Immutable public final class SwitchColors {
+  }
+
+  public final class SwitchDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SwitchColors colors(optional long checkedThumbColor, optional long checkedTrackColor, optional long checkedBorderColor, optional long checkedIconColor, optional long uncheckedThumbColor, optional long uncheckedTrackColor, optional long uncheckedBorderColor, optional long uncheckedIconColor, optional long disabledCheckedThumbColor, optional long disabledCheckedTrackColor, optional long disabledCheckedBorderColor, optional long disabledCheckedIconColor, optional long disabledUncheckedThumbColor, optional long disabledUncheckedTrackColor, optional long disabledUncheckedBorderColor, optional long disabledUncheckedIconColor);
+    method public float getIconSize();
+    property public final float IconSize;
+    field public static final androidx.compose.material3.SwitchDefaults INSTANCE;
+  }
+
+  public final class SwitchKt {
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.compose.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class TabKt {
+    method @androidx.compose.runtime.Composable public static void LeadingIconTab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TabPosition {
+    method public float getLeft();
+    method public float getRight();
+    method public float getWidth();
+    property public final float left;
+    property public final float right;
+    property public final float width;
+  }
+
+  public final class TabRowDefaults {
+    method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    field public static final androidx.compose.material3.TabRowDefaults INSTANCE;
+  }
+
+  public final class TabRowKt {
+    method @androidx.compose.runtime.Composable public static void ScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+    method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithoutLabel(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @Deprecated public float getFocusedBorderThickness();
+    method public float getFocusedIndicatorThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @Deprecated public float getUnfocusedBorderThickness();
+    method public float getUnfocusedIndicatorThickness();
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
+    property @Deprecated public final float FocusedBorderThickness;
+    property public final float FocusedIndicatorThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property @Deprecated public final float UnfocusedBorderThickness;
+    property public final float UnfocusedIndicatorThickness;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
+  }
+
+  public final class TextFieldKt {
+    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  public final class TextKt {
+    method @androidx.compose.runtime.Composable public static void ProvideTextStyle(androidx.compose.ui.text.TextStyle value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.Map<java.lang.String,? extends androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> getLocalTextStyle();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
+  }
+
+  @androidx.compose.runtime.Stable public final class TimePickerState {
+    ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
+    method public int getHour();
+    method public int getMinute();
+    method public boolean is24hour();
+    method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final int hour;
+    property public final boolean is24hour;
+    property public final int minute;
+    field public static final androidx.compose.material3.TimePickerState.Companion Companion;
+  }
+
+  public static final class TimePickerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
+  }
+
+  @androidx.compose.runtime.Immutable public final class Typography {
+    ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.ui.text.TextStyle getBodyLarge();
+    method public androidx.compose.ui.text.TextStyle getBodyMedium();
+    method public androidx.compose.ui.text.TextStyle getBodySmall();
+    method public androidx.compose.ui.text.TextStyle getDisplayLarge();
+    method public androidx.compose.ui.text.TextStyle getDisplayMedium();
+    method public androidx.compose.ui.text.TextStyle getDisplaySmall();
+    method public androidx.compose.ui.text.TextStyle getHeadlineLarge();
+    method public androidx.compose.ui.text.TextStyle getHeadlineMedium();
+    method public androidx.compose.ui.text.TextStyle getHeadlineSmall();
+    method public androidx.compose.ui.text.TextStyle getLabelLarge();
+    method public androidx.compose.ui.text.TextStyle getLabelMedium();
+    method public androidx.compose.ui.text.TextStyle getLabelSmall();
+    method public androidx.compose.ui.text.TextStyle getTitleLarge();
+    method public androidx.compose.ui.text.TextStyle getTitleMedium();
+    method public androidx.compose.ui.text.TextStyle getTitleSmall();
+    property public final androidx.compose.ui.text.TextStyle bodyLarge;
+    property public final androidx.compose.ui.text.TextStyle bodyMedium;
+    property public final androidx.compose.ui.text.TextStyle bodySmall;
+    property public final androidx.compose.ui.text.TextStyle displayLarge;
+    property public final androidx.compose.ui.text.TextStyle displayMedium;
+    property public final androidx.compose.ui.text.TextStyle displaySmall;
+    property public final androidx.compose.ui.text.TextStyle headlineLarge;
+    property public final androidx.compose.ui.text.TextStyle headlineMedium;
+    property public final androidx.compose.ui.text.TextStyle headlineSmall;
+    property public final androidx.compose.ui.text.TextStyle labelLarge;
+    property public final androidx.compose.ui.text.TextStyle labelMedium;
+    property public final androidx.compose.ui.text.TextStyle labelSmall;
+    property public final androidx.compose.ui.text.TextStyle titleLarge;
+    property public final androidx.compose.ui.text.TextStyle titleMedium;
+    property public final androidx.compose.ui.text.TextStyle titleSmall;
+  }
+
+}
+
diff --git a/compose/material3/material3/api/current.ignore b/compose/material3/material3/api/current.ignore
index 6a69117..dd3f23a 100644
--- a/compose/material3/material3/api/current.ignore
+++ b/compose/material3/material3/api/current.ignore
@@ -1,43 +1,3 @@
 // Baseline format: 1.0
-ParameterNameChange: androidx.compose.material3.SnackbarDuration#valueOf(String) parameter #0:
-    Attempted to change parameter name from name to value in method androidx.compose.material3.SnackbarDuration.valueOf
-ParameterNameChange: androidx.compose.material3.SnackbarResult#valueOf(String) parameter #0:
-    Attempted to change parameter name from name to value in method androidx.compose.material3.SnackbarResult.valueOf
-
-
-RemovedClass: androidx.compose.material3.AlertDialogKt:
-    Removed class androidx.compose.material3.AlertDialogKt
-RemovedClass: androidx.compose.material3.BadgeKt:
-    Removed class androidx.compose.material3.BadgeKt
-RemovedClass: androidx.compose.material3.DragGestureDetectorCopyKt:
-    Removed class androidx.compose.material3.DragGestureDetectorCopyKt
-RemovedClass: androidx.compose.material3.ElevationKt:
-    Removed class androidx.compose.material3.ElevationKt
-RemovedClass: androidx.compose.material3.ExposedDropdownMenuKt:
-    Removed class androidx.compose.material3.ExposedDropdownMenuKt
-RemovedClass: androidx.compose.material3.IncludeFontPaddingHelper_androidKt:
-    Removed class androidx.compose.material3.IncludeFontPaddingHelper_androidKt
-RemovedClass: androidx.compose.material3.MenuKt:
-    Removed class androidx.compose.material3.MenuKt
-RemovedClass: androidx.compose.material3.ShapesKt:
-    Removed class androidx.compose.material3.ShapesKt
-RemovedClass: androidx.compose.material3.Strings_androidKt:
-    Removed class androidx.compose.material3.Strings_androidKt
-RemovedClass: androidx.compose.material3.SwipeableKt:
-    Removed class androidx.compose.material3.SwipeableKt
-RemovedClass: androidx.compose.material3.SystemBarsDefaultInsets_androidKt:
-    Removed class androidx.compose.material3.SystemBarsDefaultInsets_androidKt
-RemovedClass: androidx.compose.material3.TextFieldDefaultsKt:
-    Removed class androidx.compose.material3.TextFieldDefaultsKt
-RemovedClass: androidx.compose.material3.TextFieldImplKt:
-    Removed class androidx.compose.material3.TextFieldImplKt
-RemovedClass: androidx.compose.material3.TonalPaletteKt:
-    Removed class androidx.compose.material3.TonalPaletteKt
-RemovedClass: androidx.compose.material3.TouchTargetKt:
-    Removed class androidx.compose.material3.TouchTargetKt
-RemovedClass: androidx.compose.material3.TypographyKt:
-    Removed class androidx.compose.material3.TypographyKt
-
-
-RemovedPackage: androidx.compose.material3.internal:
-    Removed package androidx.compose.material3.internal
+RemovedClass: androidx.compose.material3.TimePickerState:
+    Removed class androidx.compose.material3.TimePickerState
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index a0df8a5..0901450 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -826,22 +826,6 @@
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
   }
 
-  @androidx.compose.runtime.Stable public final class TimePickerState {
-    ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
-    method public int getHour();
-    method public int getMinute();
-    method public boolean is24hour();
-    method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final int hour;
-    property public final boolean is24hour;
-    property public final int minute;
-    field public static final androidx.compose.material3.TimePickerState.Companion Companion;
-  }
-
-  public static final class TimePickerState.Companion {
-    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
-  }
-
   @androidx.compose.runtime.Immutable public final class Typography {
     ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
     method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
diff --git a/compose/material3/material3/api/public_plus_experimental_1.1.0-beta02.txt b/compose/material3/material3/api/public_plus_experimental_1.1.0-beta02.txt
index 1803f32..fd0421f 100644
--- a/compose/material3/material3/api/public_plus_experimental_1.1.0-beta02.txt
+++ b/compose/material3/material3/api/public_plus_experimental_1.1.0-beta02.txt
@@ -685,7 +685,7 @@
   @androidx.compose.runtime.Immutable public final class MenuItemColors {
   }
 
-  public final class ModalBottomSheetKt {
+  public final class ModalBottomSheet_androidKt {
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
   }
diff --git a/compose/material3/material3/api/public_plus_experimental_1.1.0-beta03.txt b/compose/material3/material3/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..fd0421f
--- /dev/null
+++ b/compose/material3/material3/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,1359 @@
+// Signature format: 4.0
+package androidx.compose.material3 {
+
+  public final class AlertDialogDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getIconContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public long getTextContentColor();
+    method @androidx.compose.runtime.Composable public long getTitleContentColor();
+    method public float getTonalElevation();
+    property public final float TonalElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long iconContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final long textContentColor;
+    property @androidx.compose.runtime.Composable public final long titleContentColor;
+    field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
+  }
+
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class AndroidMenu_androidKt {
+    method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean enabled, optional androidx.compose.material3.MenuItemColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class AppBarKt {
+    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);
+    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.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 @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 @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void MediumTopAppBar(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 @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SmallTopAppBar(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 @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TopAppBar(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 @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
+  }
+
+  public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class BadgeDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    field public static final androidx.compose.material3.BadgeDefaults INSTANCE;
+  }
+
+  public final class BadgeKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Badge(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BadgedBox(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> badge, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+  }
+
+  public final class BottomAppBarDefaults {
+    method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getContainerElevation();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    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 @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;
+    field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetDefaults {
+    method @androidx.compose.runtime.Composable public void DragHandle(optional androidx.compose.ui.Modifier modifier, optional float width, optional float height, optional androidx.compose.ui.graphics.Shape shape, optional long color);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExpandedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getHiddenShape();
+    method @androidx.compose.runtime.Composable public long getScrimColor();
+    method public float getSheetPeekHeight();
+    property @androidx.compose.runtime.Composable public final long ContainerColor;
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ExpandedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape HiddenShape;
+    property @androidx.compose.runtime.Composable public final long ScrimColor;
+    property public final float SheetPeekHeight;
+    field public static final androidx.compose.material3.BottomSheetDefaults INSTANCE;
+  }
+
+  public final class BottomSheetScaffoldKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BottomSheetScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> sheetContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.BottomSheetScaffoldState scaffoldState, optional float sheetPeekHeight, optional androidx.compose.ui.graphics.Shape sheetShape, optional long sheetContainerColor, optional long sheetContentColor, optional float sheetTonalElevation, optional float sheetShadowElevation, optional kotlin.jvm.functions.Function0<kotlin.Unit>? sheetDragHandle, optional boolean sheetSwipeEnabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? topBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarHostState,kotlin.Unit> snackbarHost, optional long containerColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.BottomSheetScaffoldState rememberBottomSheetScaffoldState(optional androidx.compose.material3.SheetState bottomSheetState, optional androidx.compose.material3.SnackbarHostState snackbarHostState);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberStandardBottomSheetState(optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class BottomSheetScaffoldState {
+    ctor public BottomSheetScaffoldState(androidx.compose.material3.SheetState bottomSheetState, androidx.compose.material3.SnackbarHostState snackbarHostState);
+    method public androidx.compose.material3.SheetState getBottomSheetState();
+    method public androidx.compose.material3.SnackbarHostState getSnackbarHostState();
+    property public final androidx.compose.material3.SheetState bottomSheetState;
+    property public final androidx.compose.material3.SnackbarHostState snackbarHostState;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ButtonColors {
+  }
+
+  public final class ButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors buttonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation buttonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors elevatedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
+    method public float getIconSize();
+    method public float getIconSpacing();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke getOutlinedButtonBorder();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonWithIconContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+    property public final float IconSize;
+    property public final float IconSpacing;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonWithIconContentPadding;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledTonalShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.BorderStroke outlinedButtonBorder;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape textShape;
+    field public static final androidx.compose.material3.ButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class ButtonElevation {
+  }
+
+  public final class ButtonKt {
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardColors {
+  }
+
+  public final class CardDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors cardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation cardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors elevatedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation elevatedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedCardBorder(optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors outlinedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation outlinedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.CardDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardElevation {
+  }
+
+  public final class CardKt {
+    method @androidx.compose.runtime.Composable public static void Card(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CheckboxColors {
+  }
+
+  public final class CheckboxDefaults {
+    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);
+    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, 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);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
+  }
+
+  public final class ChipKt {
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedFilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public final class ColorScheme {
+    ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+    method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public long getBackground();
+    method public long getError();
+    method public long getErrorContainer();
+    method public long getInverseOnSurface();
+    method public long getInversePrimary();
+    method public long getInverseSurface();
+    method public long getOnBackground();
+    method public long getOnError();
+    method public long getOnErrorContainer();
+    method public long getOnPrimary();
+    method public long getOnPrimaryContainer();
+    method public long getOnSecondary();
+    method public long getOnSecondaryContainer();
+    method public long getOnSurface();
+    method public long getOnSurfaceVariant();
+    method public long getOnTertiary();
+    method public long getOnTertiaryContainer();
+    method public long getOutline();
+    method public long getOutlineVariant();
+    method public long getPrimary();
+    method public long getPrimaryContainer();
+    method public long getScrim();
+    method public long getSecondary();
+    method public long getSecondaryContainer();
+    method public long getSurface();
+    method public long getSurfaceTint();
+    method public long getSurfaceVariant();
+    method public long getTertiary();
+    method public long getTertiaryContainer();
+    property public final long background;
+    property public final long error;
+    property public final long errorContainer;
+    property public final long inverseOnSurface;
+    property public final long inversePrimary;
+    property public final long inverseSurface;
+    property public final long onBackground;
+    property public final long onError;
+    property public final long onErrorContainer;
+    property public final long onPrimary;
+    property public final long onPrimaryContainer;
+    property public final long onSecondary;
+    property public final long onSecondaryContainer;
+    property public final long onSurface;
+    property public final long onSurfaceVariant;
+    property public final long onTertiary;
+    property public final long onTertiaryContainer;
+    property public final long outline;
+    property public final long outlineVariant;
+    property public final long primary;
+    property public final long primaryContainer;
+    property public final long scrim;
+    property public final long secondary;
+    property public final long secondaryContainer;
+    property public final long surface;
+    property public final long surfaceTint;
+    property public final long surfaceVariant;
+    property public final long tertiary;
+    property public final long tertiaryContainer;
+  }
+
+  public final class ColorSchemeKt {
+    method public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
+    method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+  }
+
+  public final class ContentColorKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> getLocalContentColor();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class DatePickerColors {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DatePickerDefaults {
+    method @androidx.compose.runtime.Composable public void DatePickerHeadline(androidx.compose.material3.DatePickerState state, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+    method @androidx.compose.runtime.Composable public void DatePickerTitle(androidx.compose.material3.DatePickerState state, optional androidx.compose.ui.Modifier modifier);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.DatePickerColors colors(optional long containerColor, optional long titleContentColor, optional long headlineContentColor, optional long weekdayContentColor, optional long subheadContentColor, optional long yearContentColor, optional long currentYearContentColor, optional long selectedYearContentColor, optional long selectedYearContainerColor, optional long dayContentColor, optional long disabledDayContentColor, optional long selectedDayContentColor, optional long disabledSelectedDayContentColor, optional long selectedDayContainerColor, optional long disabledSelectedDayContainerColor, optional long todayContentColor, optional long todayDateBorderColor, optional long dayInSelectionRangeContentColor, optional long dayInSelectionRangeContainerColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public float getTonalElevation();
+    method public kotlin.ranges.IntRange getYearRange();
+    property public final float TonalElevation;
+    property public final kotlin.ranges.IntRange YearRange;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.DatePickerDefaults INSTANCE;
+    field public static final String YearAbbrMonthDaySkeleton = "yMMMd";
+    field public static final String YearMonthSkeleton = "yMMMM";
+    field public static final String YearMonthWeekdayDaySkeleton = "yMMMMEEEEd";
+  }
+
+  public final class DatePickerDialog_androidKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePickerDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional androidx.compose.ui.graphics.Shape shape, optional float tonalElevation, optional androidx.compose.material3.DatePickerColors colors, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class DatePickerFormatter {
+    ctor public DatePickerFormatter(optional String yearSelectionSkeleton, optional String selectedDateSkeleton, optional String selectedDateDescriptionSkeleton);
+  }
+
+  public final class DatePickerKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DatePicker(androidx.compose.material3.DatePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function1<? super java.lang.Long,java.lang.Boolean> dateValidator, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DatePickerState rememberDatePickerState(optional Long? initialSelectedDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DatePickerState {
+    ctor public DatePickerState(Long? initialSelectedDateMillis, Long? initialDisplayedMonthMillis, kotlin.ranges.IntRange yearRange, int initialDisplayMode);
+    method public int getDisplayMode();
+    method public Long? getSelectedDateMillis();
+    method public void setDisplayMode(int);
+    method public void setSelection(Long? dateMillis);
+    property public final int displayMode;
+    property public final Long? selectedDateMillis;
+    field public static final androidx.compose.material3.DatePickerState.Companion Companion;
+  }
+
+  public static final class DatePickerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DatePickerState,?> Saver();
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DateRangePickerDefaults {
+    method @androidx.compose.runtime.Composable public void DateRangePickerHeadline(androidx.compose.material3.DateRangePickerState state, androidx.compose.material3.DatePickerFormatter dateFormatter, optional androidx.compose.ui.Modifier modifier);
+    method @androidx.compose.runtime.Composable public void DateRangePickerTitle(androidx.compose.material3.DateRangePickerState state, optional androidx.compose.ui.Modifier modifier);
+    field public static final androidx.compose.material3.DateRangePickerDefaults INSTANCE;
+  }
+
+  public final class DateRangePickerKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DateRangePicker(androidx.compose.material3.DateRangePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DatePickerFormatter dateFormatter, optional kotlin.jvm.functions.Function1<? super java.lang.Long,java.lang.Boolean> dateValidator, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? headline, optional boolean showModeToggle, optional androidx.compose.material3.DatePickerColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DateRangePickerState rememberDateRangePickerState(optional Long? initialSelectedStartDateMillis, optional Long? initialSelectedEndDateMillis, optional Long? initialDisplayedMonthMillis, optional kotlin.ranges.IntRange yearRange, optional int initialDisplayMode);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class DateRangePickerState {
+    ctor public DateRangePickerState(Long? initialSelectedStartDateMillis, Long? initialSelectedEndDateMillis, Long? initialDisplayedMonthMillis, kotlin.ranges.IntRange yearRange, int initialDisplayMode);
+    method public int getDisplayMode();
+    method public Long? getSelectedEndDateMillis();
+    method public Long? getSelectedStartDateMillis();
+    method public void setDisplayMode(int);
+    method public void setSelection(Long? startDateMillis, Long? endDateMillis);
+    property public final int displayMode;
+    property public final Long? selectedEndDateMillis;
+    property public final Long? selectedStartDateMillis;
+    field public static final androidx.compose.material3.DateRangePickerState.Companion Companion;
+  }
+
+  public static final class DateRangePickerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DateRangePickerState,?> Saver();
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissDirection {
+    method public static androidx.compose.material3.DismissDirection valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.DismissDirection[] values();
+    enum_constant public static final androidx.compose.material3.DismissDirection EndToStart;
+    enum_constant public static final androidx.compose.material3.DismissDirection StartToEnd;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class DismissState {
+    ctor public DismissState(androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super java.lang.Float,java.lang.Float> positionalThreshold);
+    method public suspend Object? dismiss(androidx.compose.material3.DismissDirection direction, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.DismissValue getCurrentValue();
+    method public androidx.compose.material3.DismissDirection? getDismissDirection();
+    method public float getProgress();
+    method public androidx.compose.material3.DismissValue getTargetValue();
+    method public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
+    method public float requireOffset();
+    method public suspend Object? reset(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.DismissValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final androidx.compose.material3.DismissValue currentValue;
+    property public final androidx.compose.material3.DismissDirection? dismissDirection;
+    property public final float progress;
+    property public final androidx.compose.material3.DismissValue targetValue;
+    field public static final androidx.compose.material3.DismissState.Companion Companion;
+  }
+
+  public static final class DismissState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DismissState,androidx.compose.material3.DismissValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super java.lang.Float,java.lang.Float> positionalThreshold);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public enum DismissValue {
+    method public static androidx.compose.material3.DismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.DismissValue[] values();
+    enum_constant public static final androidx.compose.material3.DismissValue Default;
+    enum_constant public static final androidx.compose.material3.DismissValue DismissedToEnd;
+    enum_constant public static final androidx.compose.material3.DismissValue DismissedToStart;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class DisplayMode {
+    field public static final androidx.compose.material3.DisplayMode.Companion Companion;
+  }
+
+  public static final class DisplayMode.Companion {
+    method public int getInput();
+    method public int getPicker();
+    property public final int Input;
+    property public final int Picker;
+  }
+
+  public final class DividerDefaults {
+    method @androidx.compose.runtime.Composable public long getColor();
+    method public float getThickness();
+    property public final float Thickness;
+    property @androidx.compose.runtime.Composable public final long color;
+    field public static final androidx.compose.material3.DividerDefaults INSTANCE;
+  }
+
+  public final class DividerKt {
+    method @androidx.compose.runtime.Composable public static void Divider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+  }
+
+  public final class DrawerDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getDismissibleDrawerElevation();
+    method public float getMaximumDrawerWidth();
+    method public float getModalDrawerElevation();
+    method public float getPermanentDrawerElevation();
+    method @androidx.compose.runtime.Composable public long getScrimColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float DismissibleDrawerElevation;
+    property public final float MaximumDrawerWidth;
+    property public final float ModalDrawerElevation;
+    property public final float PermanentDrawerElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long scrimColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.DrawerDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class DrawerState {
+    ctor public DrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+    method public suspend Object? animateTo(androidx.compose.material3.DrawerValue targetValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.DrawerValue getCurrentValue();
+    method public androidx.compose.runtime.State<java.lang.Float> getOffset();
+    method public androidx.compose.material3.DrawerValue getTargetValue();
+    method public boolean isAnimationRunning();
+    method public boolean isClosed();
+    method public boolean isOpen();
+    method public suspend Object? open(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.DrawerValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final androidx.compose.material3.DrawerValue currentValue;
+    property public final boolean isAnimationRunning;
+    property public final boolean isClosed;
+    property public final boolean isOpen;
+    property public final androidx.compose.runtime.State<java.lang.Float> offset;
+    property public final androidx.compose.material3.DrawerValue targetValue;
+    field public static final androidx.compose.material3.DrawerState.Companion Companion;
+  }
+
+  public static final class DrawerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DrawerState,androidx.compose.material3.DrawerValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public enum DrawerValue {
+    method public static androidx.compose.material3.DrawerValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.DrawerValue[] values();
+    enum_constant public static final androidx.compose.material3.DrawerValue Closed;
+    enum_constant public static final androidx.compose.material3.DrawerValue Open;
+  }
+
+  public final class DynamicTonalPaletteKt {
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicDarkColorScheme(android.content.Context context);
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicLightColorScheme(android.content.Context context);
+  }
+
+  @kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMaterial3Api {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public interface ExposedDropdownMenuBoxScope {
+    method @androidx.compose.runtime.Composable public default void ExposedDropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method public androidx.compose.ui.Modifier exposedDropdownSize(androidx.compose.ui.Modifier, optional boolean matchTextFieldWidth);
+    method public androidx.compose.ui.Modifier menuAnchor(androidx.compose.ui.Modifier);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class ExposedDropdownMenuDefaults {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TrailingIcon(boolean expanded);
+    method public androidx.compose.foundation.layout.PaddingValues getItemContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ItemContentPadding;
+    field public static final androidx.compose.material3.ExposedDropdownMenuDefaults INSTANCE;
+  }
+
+  public final class ExposedDropdownMenuKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ExposedDropdownMenuBox(boolean expanded, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onExpandedChange, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.material3.ExposedDropdownMenuBoxScope,kotlin.Unit> content);
+  }
+
+  @kotlin.jvm.JvmInline public final value class FabPosition {
+    field public static final androidx.compose.material3.FabPosition.Companion Companion;
+  }
+
+  public static final class FabPosition.Companion {
+    method public int getCenter();
+    method public int getEnd();
+    property public final int Center;
+    property public final int End;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class FilterChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors elevatedFilterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation elevatedFilterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipBorder filterChipBorder(optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors filterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation filterChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.FilterChipDefaults INSTANCE;
+  }
+
+  public final class FloatingActionButtonDefaults {
+    method public androidx.compose.material3.FloatingActionButtonElevation bottomAppBarFabElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation elevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExtendedFabShape();
+    method public float getLargeIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getLargeShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getSmallShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation loweredElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    property public final float LargeIconSize;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape extendedFabShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape largeShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape smallShape;
+    field public static final androidx.compose.material3.FloatingActionButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public class FloatingActionButtonElevation {
+  }
+
+  public final class FloatingActionButtonKt {
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean expanded, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void LargeFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void SmallFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconButtonColors {
+  }
+
+  public final class IconButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    field public static final androidx.compose.material3.IconButtonDefaults INSTANCE;
+  }
+
+  public final class IconButtonKt {
+    method @androidx.compose.runtime.Composable public static void FilledIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(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.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class IconKt {
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconToggleButtonColors {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class InputChipDefaults {
+    method public float getAvatarSize();
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipBorder inputChipBorder(optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors inputChipColors(optional long containerColor, optional long labelColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation inputChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float AvatarSize;
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.InputChipDefaults INSTANCE;
+  }
+
+  public final class InteractiveComponentSizeKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumInteractiveComponentEnforcement();
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> getLocalMinimumTouchTargetEnforcement();
+    method public static androidx.compose.ui.Modifier minimumInteractiveComponentSize(androidx.compose.ui.Modifier);
+    property @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumInteractiveComponentEnforcement;
+    property @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api public static final androidx.compose.runtime.ProvidableCompositionLocal<java.lang.Boolean> LocalMinimumTouchTargetEnforcement;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ListItemColors {
+  }
+
+  public final class ListItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ListItemColors colors(optional long containerColor, optional long headlineColor, optional long leadingIconColor, optional long overlineColor, optional long supportingColor, optional long trailingIconColor, optional long disabledHeadlineColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContainerColor();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContentColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long containerColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long contentColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.ListItemDefaults INSTANCE;
+  }
+
+  public final class ListItemKt {
+    method @androidx.compose.runtime.Composable public static void ListItem(kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional androidx.compose.material3.ListItemColors colors, optional float tonalElevation, optional float shadowElevation);
+  }
+
+  public final class MaterialTheme {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
+    field public static final androidx.compose.material3.MaterialTheme INSTANCE;
+  }
+
+  public final class MaterialThemeKt {
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class MenuDefaults {
+    method public androidx.compose.foundation.layout.PaddingValues getDropdownMenuItemContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.MenuItemColors itemColors(optional long textColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledTextColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    property public final androidx.compose.foundation.layout.PaddingValues DropdownMenuItemContentPadding;
+    field public static final androidx.compose.material3.MenuDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class MenuItemColors {
+  }
+
+  public final class ModalBottomSheet_androidKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+  }
+
+  public final class NavigationBarDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationBarItemColors {
+  }
+
+  public final class NavigationBarItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationBarItemDefaults INSTANCE;
+  }
+
+  public final class NavigationBarKt {
+    method @androidx.compose.runtime.Composable public static void NavigationBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, 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 NavigationBarItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationBarItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public interface NavigationDrawerItemColors {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> badgeColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean selected);
+  }
+
+  public final class NavigationDrawerItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationDrawerItemColors colors(optional long selectedContainerColor, optional long unselectedContainerColor, optional long selectedIconColor, optional long unselectedIconColor, optional long selectedTextColor, optional long unselectedTextColor, optional long selectedBadgeColor, optional long unselectedBadgeColor);
+    method public androidx.compose.foundation.layout.PaddingValues getItemPadding();
+    property public final androidx.compose.foundation.layout.PaddingValues ItemPadding;
+    field public static final androidx.compose.material3.NavigationDrawerItemDefaults INSTANCE;
+  }
+
+  public final class NavigationDrawerKt {
+    method @androidx.compose.runtime.Composable public static void DismissibleDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DismissibleNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(kotlin.jvm.functions.Function0<kotlin.Unit> label, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.NavigationDrawerItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void PermanentDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void PermanentNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static androidx.compose.material3.DrawerState rememberDrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public final class NavigationRailDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property @androidx.compose.runtime.Composable public final long ContainerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationRailDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationRailItemColors {
+  }
+
+  public final class NavigationRailItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationRailItemDefaults INSTANCE;
+  }
+
+  public final class NavigationRailKt {
+    method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationRailItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Immutable public final class OutlinedTextFieldDefaults {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method public float getFocusedBorderThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public float getUnfocusedBorderThickness();
+    property public final float FocusedBorderThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final float UnfocusedBorderThickness;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.OutlinedTextFieldDefaults INSTANCE;
+  }
+
+  public final class OutlinedTextFieldKt {
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class PlainTooltipState {
+    ctor public PlainTooltipState();
+    method public suspend Object? dismiss(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public boolean isVisible();
+    method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public boolean isVisible;
+  }
+
+  public final class ProgressIndicatorDefaults {
+    method @androidx.compose.runtime.Composable public long getCircularColor();
+    method public int getCircularDeterminateStrokeCap();
+    method public int getCircularIndeterminateStrokeCap();
+    method public float getCircularStrokeWidth();
+    method @androidx.compose.runtime.Composable public long getCircularTrackColor();
+    method @androidx.compose.runtime.Composable public long getLinearColor();
+    method public int getLinearStrokeCap();
+    method @androidx.compose.runtime.Composable public long getLinearTrackColor();
+    method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getProgressAnimationSpec();
+    property public final int CircularDeterminateStrokeCap;
+    property public final int CircularIndeterminateStrokeCap;
+    property public final float CircularStrokeWidth;
+    property public final int LinearStrokeCap;
+    property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> ProgressAnimationSpec;
+    property @androidx.compose.runtime.Composable public final long circularColor;
+    property @androidx.compose.runtime.Composable public final long circularTrackColor;
+    property @androidx.compose.runtime.Composable public final long linearColor;
+    property @androidx.compose.runtime.Composable public final long linearTrackColor;
+    field public static final androidx.compose.material3.ProgressIndicatorDefaults INSTANCE;
+  }
+
+  public final class ProgressIndicatorKt {
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+  }
+
+  @androidx.compose.runtime.Immutable public final class RadioButtonColors {
+  }
+
+  public final class RadioButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.RadioButtonColors colors(optional long selectedColor, optional long unselectedColor, optional long disabledSelectedColor, optional long disabledUnselectedColor);
+    field public static final androidx.compose.material3.RadioButtonDefaults INSTANCE;
+  }
+
+  public final class RadioButtonKt {
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.RadioButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @androidx.compose.runtime.Stable public final class RichTooltipColors {
+    ctor public RichTooltipColors(long containerColor, long contentColor, long titleContentColor, long actionContentColor);
+    method public long getActionContentColor();
+    method public long getContainerColor();
+    method public long getContentColor();
+    method public long getTitleContentColor();
+    property public final long actionContentColor;
+    property public final long containerColor;
+    property public final long contentColor;
+    property public final long titleContentColor;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class RichTooltipState {
+    ctor public RichTooltipState();
+    method public suspend Object? dismiss(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public boolean isVisible();
+    method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public boolean isVisible;
+  }
+
+  public final class ScaffoldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+    field public static final androidx.compose.material3.ScaffoldDefaults INSTANCE;
+  }
+
+  public final class ScaffoldKt {
+    method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.WindowInsets contentWindowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SearchBarColors {
+    method public long getContainerColor();
+    method public long getDividerColor();
+    method public androidx.compose.material3.TextFieldColors getInputFieldColors();
+    property public final long containerColor;
+    property public final long dividerColor;
+    property public final androidx.compose.material3.TextFieldColors inputFieldColors;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class SearchBarDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SearchBarColors colors(optional long containerColor, optional long dividerColor, optional androidx.compose.material3.TextFieldColors inputFieldColors);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getDockedShape();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFullScreenShape();
+    method public float getInputFieldHeight();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getInputFieldShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors inputFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors! inputFieldColors(optional long textColor, optional long disabledTextColor, optional long cursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+    property public final float Elevation;
+    property public final float InputFieldHeight;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape dockedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape fullScreenShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape inputFieldShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.SearchBarDefaults INSTANCE;
+  }
+
+  public final class SearchBarKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void DockedSearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SearchBar(String query, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onQueryChange, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onSearch, boolean active, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onActiveChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SearchBarColors colors, optional float tonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SelectableChipBorder {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SelectableChipColors {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class SelectableChipElevation {
+  }
+
+  public final class ShapeDefaults {
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Small;
+    field public static final androidx.compose.material3.ShapeDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class SheetState {
+    ctor public SheetState(boolean skipPartiallyExpanded, optional androidx.compose.material3.SheetValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange, optional boolean skipHiddenState);
+    method public suspend Object? expand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.SheetValue getCurrentValue();
+    method public boolean getHasExpandedState();
+    method public boolean getHasPartiallyExpandedState();
+    method public androidx.compose.material3.SheetValue getTargetValue();
+    method public suspend Object? hide(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public boolean isVisible();
+    method public suspend Object? partialExpand(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public float requireOffset();
+    method public suspend Object? show(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final androidx.compose.material3.SheetValue currentValue;
+    property public final boolean hasExpandedState;
+    property public final boolean hasPartiallyExpandedState;
+    property public final boolean isVisible;
+    property public final androidx.compose.material3.SheetValue targetValue;
+    field public static final androidx.compose.material3.SheetState.Companion Companion;
+  }
+
+  public static final class SheetState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.SheetState,androidx.compose.material3.SheetValue> Saver(boolean skipPartiallyExpanded, kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public enum SheetValue {
+    method public static androidx.compose.material3.SheetValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SheetValue[] values();
+    enum_constant public static final androidx.compose.material3.SheetValue Expanded;
+    enum_constant public static final androidx.compose.material3.SheetValue Hidden;
+    enum_constant public static final androidx.compose.material3.SheetValue PartiallyExpanded;
+  }
+
+  @androidx.compose.runtime.Immutable public final class SliderColors {
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderDefaults {
+    method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
+    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
+    field public static final androidx.compose.material3.SliderDefaults INSTANCE;
+  }
+
+  public final class SliderKt {
+    method @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource startInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource endInteractionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderPositions,kotlin.Unit> startThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderPositions,kotlin.Unit> endThumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderPositions,kotlin.Unit> track, optional int steps);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderPositions,kotlin.Unit> thumb, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SliderPositions,kotlin.Unit> track, optional int steps);
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderPositions {
+    ctor public SliderPositions(optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> initialActiveRange, optional float[] initialTickFractions);
+    method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getActiveRange();
+    method public float[] getTickFractions();
+    property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> activeRange;
+    property public final float[] tickFractions;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarData {
+    method public void dismiss();
+    method public androidx.compose.material3.SnackbarVisuals getVisuals();
+    method public void performAction();
+    property public abstract androidx.compose.material3.SnackbarVisuals visuals;
+  }
+
+  public final class SnackbarDefaults {
+    method @androidx.compose.runtime.Composable public long getActionColor();
+    method @androidx.compose.runtime.Composable public long getActionContentColor();
+    method @androidx.compose.runtime.Composable public long getColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method @androidx.compose.runtime.Composable public long getDismissActionContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property @androidx.compose.runtime.Composable public final long actionColor;
+    property @androidx.compose.runtime.Composable public final long actionContentColor;
+    property @androidx.compose.runtime.Composable public final long color;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    property @androidx.compose.runtime.Composable public final long dismissActionContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SnackbarDefaults INSTANCE;
+  }
+
+  public enum SnackbarDuration {
+    method public static androidx.compose.material3.SnackbarDuration valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarDuration[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Indefinite;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Long;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Short;
+  }
+
+  public final class SnackbarHostKt {
+    method @androidx.compose.runtime.Composable public static void SnackbarHost(androidx.compose.material3.SnackbarHostState hostState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarData,kotlin.Unit> snackbar);
+  }
+
+  @androidx.compose.runtime.Stable public final class SnackbarHostState {
+    ctor public SnackbarHostState();
+    method public androidx.compose.material3.SnackbarData? getCurrentSnackbarData();
+    method public suspend Object? showSnackbar(String message, optional String? actionLabel, optional boolean withDismissAction, optional androidx.compose.material3.SnackbarDuration duration, optional kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    method public suspend Object? showSnackbar(androidx.compose.material3.SnackbarVisuals visuals, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    property public final androidx.compose.material3.SnackbarData? currentSnackbarData;
+  }
+
+  public final class SnackbarKt {
+    method @androidx.compose.runtime.Composable public static void Snackbar(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissAction, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionContentColor, optional long dismissActionContentColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Snackbar(androidx.compose.material3.SnackbarData snackbarData, optional androidx.compose.ui.Modifier modifier, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionColor, optional long actionContentColor, optional long dismissActionContentColor);
+  }
+
+  public enum SnackbarResult {
+    method public static androidx.compose.material3.SnackbarResult valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarResult[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarResult ActionPerformed;
+    enum_constant public static final androidx.compose.material3.SnackbarResult Dismissed;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarVisuals {
+    method public String? getActionLabel();
+    method public androidx.compose.material3.SnackbarDuration getDuration();
+    method public String getMessage();
+    method public boolean getWithDismissAction();
+    property public abstract String? actionLabel;
+    property public abstract androidx.compose.material3.SnackbarDuration duration;
+    property public abstract String message;
+    property public abstract boolean withDismissAction;
+  }
+
+  public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+  }
+
+  public final class SurfaceKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(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.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissDefaults {
+    method public kotlin.jvm.functions.Function2<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float> getFixedPositionalThreshold();
+    property public final kotlin.jvm.functions.Function2<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float> FixedPositionalThreshold;
+    field public static final androidx.compose.material3.SwipeToDismissDefaults INSTANCE;
+  }
+
+  public final class SwipeToDismissKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.DismissState state, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set<? extends androidx.compose.material3.DismissDirection> directions);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.DismissState rememberDismissState(optional androidx.compose.material3.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DismissValue,java.lang.Boolean> confirmValueChange, optional kotlin.jvm.functions.Function2<? super androidx.compose.ui.unit.Density,? super java.lang.Float,java.lang.Float> positionalThreshold);
+  }
+
+  @androidx.compose.runtime.Immutable public final class SwitchColors {
+  }
+
+  public final class SwitchDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SwitchColors colors(optional long checkedThumbColor, optional long checkedTrackColor, optional long checkedBorderColor, optional long checkedIconColor, optional long uncheckedThumbColor, optional long uncheckedTrackColor, optional long uncheckedBorderColor, optional long uncheckedIconColor, optional long disabledCheckedThumbColor, optional long disabledCheckedTrackColor, optional long disabledCheckedBorderColor, optional long disabledCheckedIconColor, optional long disabledUncheckedThumbColor, optional long disabledUncheckedTrackColor, optional long disabledUncheckedBorderColor, optional long disabledUncheckedIconColor);
+    method public float getIconSize();
+    property public final float IconSize;
+    field public static final androidx.compose.material3.SwitchDefaults INSTANCE;
+  }
+
+  public final class SwitchKt {
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.compose.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class TabKt {
+    method @androidx.compose.runtime.Composable public static void LeadingIconTab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TabPosition {
+    method public float getLeft();
+    method public float getRight();
+    method public float getWidth();
+    property public final float left;
+    property public final float right;
+    property public final float width;
+  }
+
+  public final class TabRowDefaults {
+    method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    field public static final androidx.compose.material3.TabRowDefaults INSTANCE;
+  }
+
+  public final class TabRowKt {
+    method @androidx.compose.runtime.Composable public static void ScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+    method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void ContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void DecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<? extends kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<? extends kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit> container);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithoutLabel(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @Deprecated public float getFocusedBorderThickness();
+    method public float getFocusedIndicatorThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @Deprecated public float getUnfocusedBorderThickness();
+    method public float getUnfocusedIndicatorThickness();
+    method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long containerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
+    property @Deprecated public final float FocusedBorderThickness;
+    property public final float FocusedIndicatorThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property @Deprecated public final float UnfocusedBorderThickness;
+    property public final float UnfocusedIndicatorThickness;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
+  }
+
+  public final class TextFieldKt {
+    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  public final class TextKt {
+    method @androidx.compose.runtime.Composable public static void ProvideTextStyle(androidx.compose.ui.text.TextStyle value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.Map<java.lang.String,? extends androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> getLocalTextStyle();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class TimePickerColors {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TimePickerColors colors(optional long clockDialColor, optional long clockDialSelectedContentColor, optional long clockDialUnselectedContentColor, optional long selectorColor, optional long containerColor, optional long periodSelectorBorderColor, optional long periodSelectorSelectedContainerColor, optional long periodSelectorUnselectedContainerColor, optional long periodSelectorSelectedContentColor, optional long periodSelectorUnselectedContentColor, optional long timeSelectorSelectedContainerColor, optional long timeSelectorUnselectedContainerColor, optional long timeSelectorSelectedContentColor, optional long timeSelectorUnselectedContentColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public int layoutType();
+    field public static final androidx.compose.material3.TimePickerDefaults INSTANCE;
+  }
+
+  public final class TimePickerKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimeInput(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TimePicker(androidx.compose.material3.TimePickerState state, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.TimePickerColors colors, optional int layoutType);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TimePickerState rememberTimePickerState(optional int initialHour, optional int initialMinute, optional boolean is24Hour);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TimePickerLayoutType {
+    field public static final androidx.compose.material3.TimePickerLayoutType.Companion Companion;
+  }
+
+  public static final class TimePickerLayoutType.Companion {
+    method public int getHorizontal();
+    method public int getVertical();
+    property public final int Horizontal;
+    property public final int Vertical;
+  }
+
+  @androidx.compose.runtime.Stable public final class TimePickerState {
+    ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
+    method public int getHour();
+    method public int getMinute();
+    method public boolean is24hour();
+    method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final int hour;
+    property public final boolean is24hour;
+    property public final int minute;
+    field public static final androidx.compose.material3.TimePickerState.Companion Companion;
+  }
+
+  public static final class TimePickerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public interface TooltipBoxScope {
+    method public androidx.compose.ui.Modifier tooltipAnchor(androidx.compose.ui.Modifier);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class TooltipDefaults {
+    method @androidx.compose.runtime.Composable public long getPlainTooltipContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getPlainTooltipContainerShape();
+    method @androidx.compose.runtime.Composable public long getPlainTooltipContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getRichTooltipContainerShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.RichTooltipColors richTooltipColors(optional long containerColor, optional long contentColor, optional long titleContentColor, optional long actionContentColor);
+    property @androidx.compose.runtime.Composable public final long plainTooltipContainerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape plainTooltipContainerShape;
+    property @androidx.compose.runtime.Composable public final long plainTooltipContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape richTooltipContainerShape;
+    field public static final androidx.compose.material3.TooltipDefaults INSTANCE;
+  }
+
+  public final class TooltipKt {
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> tooltip, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.PlainTooltipState tooltipState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltipBox(kotlin.jvm.functions.Function0<kotlin.Unit> text, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.RichTooltipState tooltipState, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipBoxScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api public final class TopAppBarDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors centerAlignedTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior enterAlwaysScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior exitUntilCollapsedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors largeTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors mediumTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarScrollBehavior pinnedScrollBehavior(optional androidx.compose.material3.TopAppBarState state, optional kotlin.jvm.functions.Function0<java.lang.Boolean> canScroll);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors smallTopAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TopAppBarColors topAppBarColors(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.TopAppBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface TopAppBarScrollBehavior {
+    method public androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? getFlingAnimationSpec();
+    method public androidx.compose.ui.input.nestedscroll.NestedScrollConnection getNestedScrollConnection();
+    method public androidx.compose.animation.core.AnimationSpec<java.lang.Float>? getSnapAnimationSpec();
+    method public androidx.compose.material3.TopAppBarState getState();
+    method public boolean isPinned();
+    property public abstract androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float>? flingAnimationSpec;
+    property public abstract boolean isPinned;
+    property public abstract androidx.compose.ui.input.nestedscroll.NestedScrollConnection nestedScrollConnection;
+    property public abstract androidx.compose.animation.core.AnimationSpec<java.lang.Float>? snapAnimationSpec;
+    property public abstract androidx.compose.material3.TopAppBarState state;
+  }
+
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarState {
+    ctor public TopAppBarState(float initialHeightOffsetLimit, float initialHeightOffset, float initialContentOffset);
+    method public float getCollapsedFraction();
+    method public float getContentOffset();
+    method public float getHeightOffset();
+    method public float getHeightOffsetLimit();
+    method public float getOverlappedFraction();
+    method public void setContentOffset(float);
+    method public void setHeightOffset(float);
+    method public void setHeightOffsetLimit(float);
+    property public final float collapsedFraction;
+    property public final float contentOffset;
+    property public final float heightOffset;
+    property public final float heightOffsetLimit;
+    property public final float overlappedFraction;
+    field public static final androidx.compose.material3.TopAppBarState.Companion Companion;
+  }
+
+  public static final class TopAppBarState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TopAppBarState,?> Saver;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Typography {
+    ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.ui.text.TextStyle getBodyLarge();
+    method public androidx.compose.ui.text.TextStyle getBodyMedium();
+    method public androidx.compose.ui.text.TextStyle getBodySmall();
+    method public androidx.compose.ui.text.TextStyle getDisplayLarge();
+    method public androidx.compose.ui.text.TextStyle getDisplayMedium();
+    method public androidx.compose.ui.text.TextStyle getDisplaySmall();
+    method public androidx.compose.ui.text.TextStyle getHeadlineLarge();
+    method public androidx.compose.ui.text.TextStyle getHeadlineMedium();
+    method public androidx.compose.ui.text.TextStyle getHeadlineSmall();
+    method public androidx.compose.ui.text.TextStyle getLabelLarge();
+    method public androidx.compose.ui.text.TextStyle getLabelMedium();
+    method public androidx.compose.ui.text.TextStyle getLabelSmall();
+    method public androidx.compose.ui.text.TextStyle getTitleLarge();
+    method public androidx.compose.ui.text.TextStyle getTitleMedium();
+    method public androidx.compose.ui.text.TextStyle getTitleSmall();
+    property public final androidx.compose.ui.text.TextStyle bodyLarge;
+    property public final androidx.compose.ui.text.TextStyle bodyMedium;
+    property public final androidx.compose.ui.text.TextStyle bodySmall;
+    property public final androidx.compose.ui.text.TextStyle displayLarge;
+    property public final androidx.compose.ui.text.TextStyle displayMedium;
+    property public final androidx.compose.ui.text.TextStyle displaySmall;
+    property public final androidx.compose.ui.text.TextStyle headlineLarge;
+    property public final androidx.compose.ui.text.TextStyle headlineMedium;
+    property public final androidx.compose.ui.text.TextStyle headlineSmall;
+    property public final androidx.compose.ui.text.TextStyle labelLarge;
+    property public final androidx.compose.ui.text.TextStyle labelMedium;
+    property public final androidx.compose.ui.text.TextStyle labelSmall;
+    property public final androidx.compose.ui.text.TextStyle titleLarge;
+    property public final androidx.compose.ui.text.TextStyle titleMedium;
+    property public final androidx.compose.ui.text.TextStyle titleSmall;
+  }
+
+}
+
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index 1803f32..c9a1a36 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -685,7 +685,7 @@
   @androidx.compose.runtime.Immutable public final class MenuItemColors {
   }
 
-  public final class ModalBottomSheetKt {
+  public final class ModalBottomSheet_androidKt {
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ModalBottomSheet(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SheetState sheetState, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional float tonalElevation, optional long scrimColor, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dragHandle, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SheetState rememberModalBottomSheetState(optional boolean skipPartiallyExpanded, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SheetValue,java.lang.Boolean> confirmValueChange);
   }
@@ -1229,7 +1229,7 @@
     property public final int Vertical;
   }
 
-  @androidx.compose.runtime.Stable public final class TimePickerState {
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TimePickerState {
     ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
     method public int getHour();
     method public int getMinute();
diff --git a/compose/material3/material3/api/res-1.1.0-beta03.txt b/compose/material3/material3/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/compose/material3/material3/api/res-1.1.0-beta03.txt
diff --git a/compose/material3/material3/api/restricted_1.1.0-beta03.txt b/compose/material3/material3/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..a0df8a5
--- /dev/null
+++ b/compose/material3/material3/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,881 @@
+// Signature format: 4.0
+package androidx.compose.material3 {
+
+  public final class AlertDialogDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getIconContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public long getTextContentColor();
+    method @androidx.compose.runtime.Composable public long getTitleContentColor();
+    method public float getTonalElevation();
+    property public final float TonalElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long iconContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final long textContentColor;
+    property @androidx.compose.runtime.Composable public final long titleContentColor;
+    field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
+  }
+
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
+  public final class AndroidMenu_androidKt {
+    method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean enabled, optional androidx.compose.material3.MenuItemColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class AppBarKt {
+    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);
+    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);
+  }
+
+  public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+  }
+
+  public final class BottomAppBarDefaults {
+    method @androidx.compose.runtime.Composable public long getBottomAppBarFabColor();
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getContainerElevation();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    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 @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;
+    field public static final androidx.compose.material3.BottomAppBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class ButtonColors {
+  }
+
+  public final class ButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors buttonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation buttonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors elevatedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
+    method public float getIconSize();
+    method public float getIconSpacing();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke getOutlinedButtonBorder();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonContentPadding();
+    method public androidx.compose.foundation.layout.PaddingValues getTextButtonWithIconContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+    property public final float IconSize;
+    property public final float IconSpacing;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonContentPadding;
+    property public final androidx.compose.foundation.layout.PaddingValues TextButtonWithIconContentPadding;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledTonalShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.BorderStroke outlinedButtonBorder;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape textShape;
+    field public static final androidx.compose.material3.ButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class ButtonElevation {
+  }
+
+  public final class ButtonKt {
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ButtonColors colors, optional androidx.compose.material3.ButtonElevation? elevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardColors {
+  }
+
+  public final class CardDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors cardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation cardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors elevatedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation elevatedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedCardBorder(optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardColors outlinedCardColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.CardElevation outlinedCardElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape elevatedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.CardDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class CardElevation {
+  }
+
+  public final class CardKt {
+    method @androidx.compose.runtime.Composable public static void Card(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ElevatedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedCard(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.CardColors colors, optional androidx.compose.material3.CardElevation elevation, optional androidx.compose.foundation.BorderStroke border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class CheckboxColors {
+  }
+
+  public final class CheckboxDefaults {
+    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);
+    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, 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);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
+  }
+
+  public final class ChipKt {
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public final class ColorScheme {
+    ctor public ColorScheme(long primary, long onPrimary, long primaryContainer, long onPrimaryContainer, long inversePrimary, long secondary, long onSecondary, long secondaryContainer, long onSecondaryContainer, long tertiary, long onTertiary, long tertiaryContainer, long onTertiaryContainer, long background, long onBackground, long surface, long onSurface, long surfaceVariant, long onSurfaceVariant, long surfaceTint, long inverseSurface, long inverseOnSurface, long error, long onError, long errorContainer, long onErrorContainer, long outline, long outlineVariant, long scrim);
+    method public androidx.compose.material3.ColorScheme copy(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public long getBackground();
+    method public long getError();
+    method public long getErrorContainer();
+    method public long getInverseOnSurface();
+    method public long getInversePrimary();
+    method public long getInverseSurface();
+    method public long getOnBackground();
+    method public long getOnError();
+    method public long getOnErrorContainer();
+    method public long getOnPrimary();
+    method public long getOnPrimaryContainer();
+    method public long getOnSecondary();
+    method public long getOnSecondaryContainer();
+    method public long getOnSurface();
+    method public long getOnSurfaceVariant();
+    method public long getOnTertiary();
+    method public long getOnTertiaryContainer();
+    method public long getOutline();
+    method public long getOutlineVariant();
+    method public long getPrimary();
+    method public long getPrimaryContainer();
+    method public long getScrim();
+    method public long getSecondary();
+    method public long getSecondaryContainer();
+    method public long getSurface();
+    method public long getSurfaceTint();
+    method public long getSurfaceVariant();
+    method public long getTertiary();
+    method public long getTertiaryContainer();
+    property public final long background;
+    property public final long error;
+    property public final long errorContainer;
+    property public final long inverseOnSurface;
+    property public final long inversePrimary;
+    property public final long inverseSurface;
+    property public final long onBackground;
+    property public final long onError;
+    property public final long onErrorContainer;
+    property public final long onPrimary;
+    property public final long onPrimaryContainer;
+    property public final long onSecondary;
+    property public final long onSecondaryContainer;
+    property public final long onSurface;
+    property public final long onSurfaceVariant;
+    property public final long onTertiary;
+    property public final long onTertiaryContainer;
+    property public final long outline;
+    property public final long outlineVariant;
+    property public final long primary;
+    property public final long primaryContainer;
+    property public final long scrim;
+    property public final long secondary;
+    property public final long secondaryContainer;
+    property public final long surface;
+    property public final long surfaceTint;
+    property public final long surfaceVariant;
+    property public final long tertiary;
+    property public final long tertiaryContainer;
+  }
+
+  public final class ColorSchemeKt {
+    method public static long contentColorFor(androidx.compose.material3.ColorScheme, long backgroundColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static long contentColorFor(long backgroundColor);
+    method public static androidx.compose.material3.ColorScheme darkColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static androidx.compose.material3.ColorScheme lightColorScheme(optional long primary, optional long onPrimary, optional long primaryContainer, optional long onPrimaryContainer, optional long inversePrimary, optional long secondary, optional long onSecondary, optional long secondaryContainer, optional long onSecondaryContainer, optional long tertiary, optional long onTertiary, optional long tertiaryContainer, optional long onTertiaryContainer, optional long background, optional long onBackground, optional long surface, optional long onSurface, optional long surfaceVariant, optional long onSurfaceVariant, optional long surfaceTint, optional long inverseSurface, optional long inverseOnSurface, optional long error, optional long onError, optional long errorContainer, optional long onErrorContainer, optional long outline, optional long outlineVariant, optional long scrim);
+    method public static long surfaceColorAtElevation(androidx.compose.material3.ColorScheme, float elevation);
+  }
+
+  public final class ContentColorKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> getLocalContentColor();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.graphics.Color> LocalContentColor;
+  }
+
+  public final class DividerDefaults {
+    method @androidx.compose.runtime.Composable public long getColor();
+    method public float getThickness();
+    property public final float Thickness;
+    property @androidx.compose.runtime.Composable public final long color;
+    field public static final androidx.compose.material3.DividerDefaults INSTANCE;
+  }
+
+  public final class DividerKt {
+    method @androidx.compose.runtime.Composable public static void Divider(optional androidx.compose.ui.Modifier modifier, optional float thickness, optional long color);
+  }
+
+  public final class DrawerDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getDismissibleDrawerElevation();
+    method public float getMaximumDrawerWidth();
+    method public float getModalDrawerElevation();
+    method public float getPermanentDrawerElevation();
+    method @androidx.compose.runtime.Composable public long getScrimColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float DismissibleDrawerElevation;
+    property public final float MaximumDrawerWidth;
+    property public final float ModalDrawerElevation;
+    property public final float PermanentDrawerElevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long scrimColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.DrawerDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class DrawerState {
+    ctor public DrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+    method public suspend Object? animateTo(androidx.compose.material3.DrawerValue targetValue, androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? close(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public androidx.compose.material3.DrawerValue getCurrentValue();
+    method public androidx.compose.runtime.State<java.lang.Float> getOffset();
+    method public androidx.compose.material3.DrawerValue getTargetValue();
+    method public boolean isAnimationRunning();
+    method public boolean isClosed();
+    method public boolean isOpen();
+    method public suspend Object? open(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? snapTo(androidx.compose.material3.DrawerValue targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final androidx.compose.material3.DrawerValue currentValue;
+    property public final boolean isAnimationRunning;
+    property public final boolean isClosed;
+    property public final boolean isOpen;
+    property public final androidx.compose.runtime.State<java.lang.Float> offset;
+    property public final androidx.compose.material3.DrawerValue targetValue;
+    field public static final androidx.compose.material3.DrawerState.Companion Companion;
+  }
+
+  public static final class DrawerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.DrawerState,androidx.compose.material3.DrawerValue> Saver(kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public enum DrawerValue {
+    method public static androidx.compose.material3.DrawerValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.DrawerValue[] values();
+    enum_constant public static final androidx.compose.material3.DrawerValue Closed;
+    enum_constant public static final androidx.compose.material3.DrawerValue Open;
+  }
+
+  public final class DynamicTonalPaletteKt {
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicDarkColorScheme(android.content.Context context);
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public static androidx.compose.material3.ColorScheme dynamicLightColorScheme(android.content.Context context);
+  }
+
+  @kotlin.jvm.JvmInline public final value class FabPosition {
+    field public static final androidx.compose.material3.FabPosition.Companion Companion;
+  }
+
+  public static final class FabPosition.Companion {
+    method public int getCenter();
+    method public int getEnd();
+    property public final int Center;
+    property public final int End;
+  }
+
+  public final class FloatingActionButtonDefaults {
+    method public androidx.compose.material3.FloatingActionButtonElevation bottomAppBarFabElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation elevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getExtendedFabShape();
+    method public float getLargeIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getLargeShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getSmallShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.FloatingActionButtonElevation loweredElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation);
+    property public final float LargeIconSize;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape extendedFabShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape largeShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape smallShape;
+    field public static final androidx.compose.material3.FloatingActionButtonDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public class FloatingActionButtonElevation {
+  }
+
+  public final class FloatingActionButtonKt {
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean expanded, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void LargeFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void SmallFloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional androidx.compose.material3.FloatingActionButtonElevation elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconButtonColors {
+  }
+
+  public final class IconButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors filledTonalIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors filledTonalIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    field public static final androidx.compose.material3.IconButtonDefaults INSTANCE;
+  }
+
+  public final class IconButtonKt {
+    method @androidx.compose.runtime.Composable public static void FilledIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void FilledTonalIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(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.IconToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.IconButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void OutlinedIconToggleButton(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.ui.graphics.Shape shape, optional androidx.compose.material3.IconToggleButtonColors colors, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class IconKt {
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+    method @androidx.compose.runtime.Composable public static void Icon(androidx.compose.ui.graphics.painter.Painter painter, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
+  }
+
+  @androidx.compose.runtime.Immutable public final class IconToggleButtonColors {
+  }
+
+  public final class InteractiveComponentSizeKt {
+    method public static androidx.compose.ui.Modifier minimumInteractiveComponentSize(androidx.compose.ui.Modifier);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ListItemColors {
+  }
+
+  public final class ListItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ListItemColors colors(optional long containerColor, optional long headlineColor, optional long leadingIconColor, optional long overlineColor, optional long supportingColor, optional long trailingIconColor, optional long disabledHeadlineColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContainerColor();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public long getContentColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long containerColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final long contentColor;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.ListItemDefaults INSTANCE;
+  }
+
+  public final class ListItemKt {
+    method @androidx.compose.runtime.Composable public static void ListItem(kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional androidx.compose.material3.ListItemColors colors, optional float tonalElevation, optional float shadowElevation);
+  }
+
+  public final class MaterialTheme {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
+    field public static final androidx.compose.material3.MaterialTheme INSTANCE;
+  }
+
+  public final class MaterialThemeKt {
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class MenuDefaults {
+    method public androidx.compose.foundation.layout.PaddingValues getDropdownMenuItemContentPadding();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.MenuItemColors itemColors(optional long textColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledTextColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor);
+    property public final androidx.compose.foundation.layout.PaddingValues DropdownMenuItemContentPadding;
+    field public static final androidx.compose.material3.MenuDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class MenuItemColors {
+  }
+
+  public final class NavigationBarDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method public float getElevation();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property public final float Elevation;
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationBarDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationBarItemColors {
+  }
+
+  public final class NavigationBarItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationBarItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationBarItemDefaults INSTANCE;
+  }
+
+  public final class NavigationBarKt {
+    method @androidx.compose.runtime.Composable public static void NavigationBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, 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 NavigationBarItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationBarItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public interface NavigationDrawerItemColors {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> badgeColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean selected);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean selected);
+  }
+
+  public final class NavigationDrawerItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationDrawerItemColors colors(optional long selectedContainerColor, optional long unselectedContainerColor, optional long selectedIconColor, optional long unselectedIconColor, optional long selectedTextColor, optional long unselectedTextColor, optional long selectedBadgeColor, optional long unselectedBadgeColor);
+    method public androidx.compose.foundation.layout.PaddingValues getItemPadding();
+    property public final androidx.compose.foundation.layout.PaddingValues ItemPadding;
+    field public static final androidx.compose.material3.NavigationDrawerItemDefaults INSTANCE;
+  }
+
+  public final class NavigationDrawerKt {
+    method @androidx.compose.runtime.Composable public static void DismissibleDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DismissibleNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ModalNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.DrawerState drawerState, optional boolean gesturesEnabled, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationDrawerItem(kotlin.jvm.functions.Function0<kotlin.Unit> label, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.NavigationDrawerItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void PermanentDrawerSheet(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape drawerShape, optional long drawerContainerColor, optional long drawerContentColor, optional float drawerTonalElevation, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void PermanentNavigationDrawer(kotlin.jvm.functions.Function0<kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static androidx.compose.material3.DrawerState rememberDrawerState(androidx.compose.material3.DrawerValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.DrawerValue,java.lang.Boolean> confirmStateChange);
+  }
+
+  public final class NavigationRailDefaults {
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
+    property @androidx.compose.runtime.Composable public final long ContainerColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
+    field public static final androidx.compose.material3.NavigationRailDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Stable public final class NavigationRailItemColors {
+  }
+
+  public final class NavigationRailItemDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor, optional long disabledIconColor, optional long disabledTextColor);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.material3.NavigationRailItemColors colors(optional long selectedIconColor, optional long selectedTextColor, optional long indicatorColor, optional long unselectedIconColor, optional long unselectedTextColor);
+    field public static final androidx.compose.material3.NavigationRailItemDefaults INSTANCE;
+  }
+
+  public final class NavigationRailKt {
+    method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.material3.NavigationRailItemColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Immutable public final class OutlinedTextFieldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method public float getFocusedBorderThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method public float getUnfocusedBorderThickness();
+    property public final float FocusedBorderThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property public final float UnfocusedBorderThickness;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.OutlinedTextFieldDefaults INSTANCE;
+  }
+
+  public final class OutlinedTextFieldKt {
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  public final class ProgressIndicatorDefaults {
+    method @androidx.compose.runtime.Composable public long getCircularColor();
+    method public int getCircularDeterminateStrokeCap();
+    method public int getCircularIndeterminateStrokeCap();
+    method public float getCircularStrokeWidth();
+    method @androidx.compose.runtime.Composable public long getCircularTrackColor();
+    method @androidx.compose.runtime.Composable public long getLinearColor();
+    method public int getLinearStrokeCap();
+    method @androidx.compose.runtime.Composable public long getLinearTrackColor();
+    method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getProgressAnimationSpec();
+    property public final int CircularDeterminateStrokeCap;
+    property public final int CircularIndeterminateStrokeCap;
+    property public final float CircularStrokeWidth;
+    property public final int LinearStrokeCap;
+    property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> ProgressAnimationSpec;
+    property @androidx.compose.runtime.Composable public final long circularColor;
+    property @androidx.compose.runtime.Composable public final long circularTrackColor;
+    property @androidx.compose.runtime.Composable public final long linearColor;
+    property @androidx.compose.runtime.Composable public final long linearTrackColor;
+    field public static final androidx.compose.material3.ProgressIndicatorDefaults INSTANCE;
+  }
+
+  public final class ProgressIndicatorKt {
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @Deprecated @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional float strokeWidth);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor, optional int strokeCap);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+    method @Deprecated @androidx.compose.runtime.Composable public static void LinearProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional long color, optional long trackColor);
+  }
+
+  @androidx.compose.runtime.Immutable public final class RadioButtonColors {
+  }
+
+  public final class RadioButtonDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.RadioButtonColors colors(optional long selectedColor, optional long unselectedColor, optional long disabledSelectedColor, optional long disabledUnselectedColor);
+    field public static final androidx.compose.material3.RadioButtonDefaults INSTANCE;
+  }
+
+  public final class RadioButtonKt {
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.material3.RadioButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class ScaffoldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+    property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+    field public static final androidx.compose.material3.ScaffoldDefaults INSTANCE;
+  }
+
+  public final class ScaffoldKt {
+    method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, optional androidx.compose.foundation.layout.WindowInsets contentWindowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
+  }
+
+  public final class ShapeDefaults {
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape ExtraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape Small;
+    field public static final androidx.compose.material3.ShapeDefaults INSTANCE;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+  }
+
+  @androidx.compose.runtime.Immutable public final class SliderColors {
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderDefaults {
+    method @androidx.compose.runtime.Composable public void Thumb(androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled, optional long thumbSize);
+    method @androidx.compose.runtime.Composable public void Track(androidx.compose.material3.SliderPositions sliderPositions, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material3.SliderColors colors, optional boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SliderColors colors(optional long thumbColor, optional long activeTrackColor, optional long activeTickColor, optional long inactiveTrackColor, optional long inactiveTickColor, optional long disabledThumbColor, optional long disabledActiveTrackColor, optional long disabledActiveTickColor, optional long disabledInactiveTrackColor, optional long disabledInactiveTickColor);
+    field public static final androidx.compose.material3.SliderDefaults INSTANCE;
+  }
+
+  public final class SliderKt {
+    method @androidx.compose.runtime.Composable public static void RangeSlider(kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> value, kotlin.jvm.functions.Function1<? super kotlin.ranges.ClosedFloatingPointRange<java.lang.Float>,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.material3.SliderColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Stable public final class SliderPositions {
+    ctor public SliderPositions(optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> initialActiveRange, optional float[] initialTickFractions);
+    method public kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> getActiveRange();
+    method public float[] getTickFractions();
+    property public final kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> activeRange;
+    property public final float[] tickFractions;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarData {
+    method public void dismiss();
+    method public androidx.compose.material3.SnackbarVisuals getVisuals();
+    method public void performAction();
+    property public abstract androidx.compose.material3.SnackbarVisuals visuals;
+  }
+
+  public final class SnackbarDefaults {
+    method @androidx.compose.runtime.Composable public long getActionColor();
+    method @androidx.compose.runtime.Composable public long getActionContentColor();
+    method @androidx.compose.runtime.Composable public long getColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method @androidx.compose.runtime.Composable public long getDismissActionContentColor();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property @androidx.compose.runtime.Composable public final long actionColor;
+    property @androidx.compose.runtime.Composable public final long actionContentColor;
+    property @androidx.compose.runtime.Composable public final long color;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    property @androidx.compose.runtime.Composable public final long dismissActionContentColor;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SnackbarDefaults INSTANCE;
+  }
+
+  public enum SnackbarDuration {
+    method public static androidx.compose.material3.SnackbarDuration valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarDuration[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Indefinite;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Long;
+    enum_constant public static final androidx.compose.material3.SnackbarDuration Short;
+  }
+
+  public final class SnackbarHostKt {
+    method @androidx.compose.runtime.Composable public static void SnackbarHost(androidx.compose.material3.SnackbarHostState hostState, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.material3.SnackbarData,kotlin.Unit> snackbar);
+  }
+
+  @androidx.compose.runtime.Stable public final class SnackbarHostState {
+    ctor public SnackbarHostState();
+    method public androidx.compose.material3.SnackbarData? getCurrentSnackbarData();
+    method public suspend Object? showSnackbar(String message, optional String? actionLabel, optional boolean withDismissAction, optional androidx.compose.material3.SnackbarDuration duration, optional kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    method public suspend Object? showSnackbar(androidx.compose.material3.SnackbarVisuals visuals, kotlin.coroutines.Continuation<? super androidx.compose.material3.SnackbarResult>);
+    property public final androidx.compose.material3.SnackbarData? currentSnackbarData;
+  }
+
+  public final class SnackbarKt {
+    method @androidx.compose.runtime.Composable public static void Snackbar(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissAction, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionContentColor, optional long dismissActionContentColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Snackbar(androidx.compose.material3.SnackbarData snackbarData, optional androidx.compose.ui.Modifier modifier, optional boolean actionOnNewLine, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long contentColor, optional long actionColor, optional long actionContentColor, optional long dismissActionContentColor);
+  }
+
+  public enum SnackbarResult {
+    method public static androidx.compose.material3.SnackbarResult valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SnackbarResult[] values();
+    enum_constant public static final androidx.compose.material3.SnackbarResult ActionPerformed;
+    enum_constant public static final androidx.compose.material3.SnackbarResult Dismissed;
+  }
+
+  @androidx.compose.runtime.Stable public interface SnackbarVisuals {
+    method public String? getActionLabel();
+    method public androidx.compose.material3.SnackbarDuration getDuration();
+    method public String getMessage();
+    method public boolean getWithDismissAction();
+    property public abstract String? actionLabel;
+    property public abstract androidx.compose.material3.SnackbarDuration duration;
+    property public abstract String message;
+    property public abstract boolean withDismissAction;
+  }
+
+  public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float elevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+  }
+
+  public final class SurfaceKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(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.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> LocalAbsoluteTonalElevation;
+  }
+
+  @androidx.compose.runtime.Immutable public final class SwitchColors {
+  }
+
+  public final class SwitchDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SwitchColors colors(optional long checkedThumbColor, optional long checkedTrackColor, optional long checkedBorderColor, optional long checkedIconColor, optional long uncheckedThumbColor, optional long uncheckedTrackColor, optional long uncheckedBorderColor, optional long uncheckedIconColor, optional long disabledCheckedThumbColor, optional long disabledCheckedTrackColor, optional long disabledCheckedBorderColor, optional long disabledCheckedIconColor, optional long disabledUncheckedThumbColor, optional long disabledUncheckedTrackColor, optional long disabledUncheckedBorderColor, optional long disabledUncheckedIconColor);
+    method public float getIconSize();
+    property public final float IconSize;
+    field public static final androidx.compose.material3.SwitchDefaults INSTANCE;
+  }
+
+  public final class SwitchKt {
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? thumbContent, optional boolean enabled, optional androidx.compose.material3.SwitchColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  public final class TabKt {
+    method @androidx.compose.runtime.Composable public static void LeadingIconTab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void Tab(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional long selectedContentColor, optional long unselectedContentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TabPosition {
+    method public float getLeft();
+    method public float getRight();
+    method public float getWidth();
+    property public final float left;
+    property public final float right;
+    property public final float width;
+  }
+
+  public final class TabRowDefaults {
+    method @androidx.compose.runtime.Composable public void Indicator(optional androidx.compose.ui.Modifier modifier, optional float height, optional long color);
+    method @androidx.compose.runtime.Composable public long getContainerColor();
+    method @androidx.compose.runtime.Composable public long getContentColor();
+    method public androidx.compose.ui.Modifier tabIndicatorOffset(androidx.compose.ui.Modifier, androidx.compose.material3.TabPosition currentTabPosition);
+    property @androidx.compose.runtime.Composable public final long containerColor;
+    property @androidx.compose.runtime.Composable public final long contentColor;
+    field public static final androidx.compose.material3.TabRowDefaults INSTANCE;
+  }
+
+  public final class TabRowKt {
+    method @androidx.compose.runtime.Composable public static void ScrollableTabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float edgePadding, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+    method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors colors(optional long focusedTextColor, optional long unfocusedTextColor, optional long disabledTextColor, optional long errorTextColor, optional long focusedContainerColor, optional long unfocusedContainerColor, optional long disabledContainerColor, optional long errorContainerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long focusedPlaceholderColor, optional long unfocusedPlaceholderColor, optional long disabledPlaceholderColor, optional long errorPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithLabel(optional float start, optional float end, optional float top, optional float bottom);
+    method public androidx.compose.foundation.layout.PaddingValues contentPaddingWithoutLabel(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
+    method @Deprecated public float getFocusedBorderThickness();
+    method public float getFocusedIndicatorThickness();
+    method public float getMinHeight();
+    method public float getMinWidth();
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @Deprecated public float getUnfocusedBorderThickness();
+    method public float getUnfocusedIndicatorThickness();
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
+    method @Deprecated public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
+    property @Deprecated public final float FocusedBorderThickness;
+    property public final float FocusedIndicatorThickness;
+    property public final float MinHeight;
+    property public final float MinWidth;
+    property @Deprecated public final float UnfocusedBorderThickness;
+    property public final float UnfocusedIndicatorThickness;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape filledShape;
+    property @Deprecated @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape outlinedShape;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
+  }
+
+  public final class TextFieldKt {
+    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+  }
+
+  public final class TextKt {
+    method @androidx.compose.runtime.Composable public static void ProvideTextStyle(androidx.compose.ui.text.TextStyle value, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional int minLines, optional java.util.Map<java.lang.String,androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(String text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Text(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.Modifier modifier, optional long color, optional long fontSize, optional androidx.compose.ui.text.font.FontStyle? fontStyle, optional androidx.compose.ui.text.font.FontWeight? fontWeight, optional androidx.compose.ui.text.font.FontFamily? fontFamily, optional long letterSpacing, optional androidx.compose.ui.text.style.TextDecoration? textDecoration, optional androidx.compose.ui.text.style.TextAlign? textAlign, optional long lineHeight, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.Map<java.lang.String,? extends androidx.compose.foundation.text.InlineTextContent> inlineContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,? extends kotlin.Unit> onTextLayout, optional androidx.compose.ui.text.TextStyle style);
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> getLocalTextStyle();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
+  }
+
+  @androidx.compose.runtime.Stable public final class TimePickerState {
+    ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
+    method public int getHour();
+    method public int getMinute();
+    method public boolean is24hour();
+    method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property public final int hour;
+    property public final boolean is24hour;
+    property public final int minute;
+    field public static final androidx.compose.material3.TimePickerState.Companion Companion;
+  }
+
+  public static final class TimePickerState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
+  }
+
+  @androidx.compose.runtime.Immutable public final class Typography {
+    ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
+    method public androidx.compose.ui.text.TextStyle getBodyLarge();
+    method public androidx.compose.ui.text.TextStyle getBodyMedium();
+    method public androidx.compose.ui.text.TextStyle getBodySmall();
+    method public androidx.compose.ui.text.TextStyle getDisplayLarge();
+    method public androidx.compose.ui.text.TextStyle getDisplayMedium();
+    method public androidx.compose.ui.text.TextStyle getDisplaySmall();
+    method public androidx.compose.ui.text.TextStyle getHeadlineLarge();
+    method public androidx.compose.ui.text.TextStyle getHeadlineMedium();
+    method public androidx.compose.ui.text.TextStyle getHeadlineSmall();
+    method public androidx.compose.ui.text.TextStyle getLabelLarge();
+    method public androidx.compose.ui.text.TextStyle getLabelMedium();
+    method public androidx.compose.ui.text.TextStyle getLabelSmall();
+    method public androidx.compose.ui.text.TextStyle getTitleLarge();
+    method public androidx.compose.ui.text.TextStyle getTitleMedium();
+    method public androidx.compose.ui.text.TextStyle getTitleSmall();
+    property public final androidx.compose.ui.text.TextStyle bodyLarge;
+    property public final androidx.compose.ui.text.TextStyle bodyMedium;
+    property public final androidx.compose.ui.text.TextStyle bodySmall;
+    property public final androidx.compose.ui.text.TextStyle displayLarge;
+    property public final androidx.compose.ui.text.TextStyle displayMedium;
+    property public final androidx.compose.ui.text.TextStyle displaySmall;
+    property public final androidx.compose.ui.text.TextStyle headlineLarge;
+    property public final androidx.compose.ui.text.TextStyle headlineMedium;
+    property public final androidx.compose.ui.text.TextStyle headlineSmall;
+    property public final androidx.compose.ui.text.TextStyle labelLarge;
+    property public final androidx.compose.ui.text.TextStyle labelMedium;
+    property public final androidx.compose.ui.text.TextStyle labelSmall;
+    property public final androidx.compose.ui.text.TextStyle titleLarge;
+    property public final androidx.compose.ui.text.TextStyle titleMedium;
+    property public final androidx.compose.ui.text.TextStyle titleSmall;
+  }
+
+}
+
diff --git a/compose/material3/material3/api/restricted_current.ignore b/compose/material3/material3/api/restricted_current.ignore
index 6a69117..dd3f23a 100644
--- a/compose/material3/material3/api/restricted_current.ignore
+++ b/compose/material3/material3/api/restricted_current.ignore
@@ -1,43 +1,3 @@
 // Baseline format: 1.0
-ParameterNameChange: androidx.compose.material3.SnackbarDuration#valueOf(String) parameter #0:
-    Attempted to change parameter name from name to value in method androidx.compose.material3.SnackbarDuration.valueOf
-ParameterNameChange: androidx.compose.material3.SnackbarResult#valueOf(String) parameter #0:
-    Attempted to change parameter name from name to value in method androidx.compose.material3.SnackbarResult.valueOf
-
-
-RemovedClass: androidx.compose.material3.AlertDialogKt:
-    Removed class androidx.compose.material3.AlertDialogKt
-RemovedClass: androidx.compose.material3.BadgeKt:
-    Removed class androidx.compose.material3.BadgeKt
-RemovedClass: androidx.compose.material3.DragGestureDetectorCopyKt:
-    Removed class androidx.compose.material3.DragGestureDetectorCopyKt
-RemovedClass: androidx.compose.material3.ElevationKt:
-    Removed class androidx.compose.material3.ElevationKt
-RemovedClass: androidx.compose.material3.ExposedDropdownMenuKt:
-    Removed class androidx.compose.material3.ExposedDropdownMenuKt
-RemovedClass: androidx.compose.material3.IncludeFontPaddingHelper_androidKt:
-    Removed class androidx.compose.material3.IncludeFontPaddingHelper_androidKt
-RemovedClass: androidx.compose.material3.MenuKt:
-    Removed class androidx.compose.material3.MenuKt
-RemovedClass: androidx.compose.material3.ShapesKt:
-    Removed class androidx.compose.material3.ShapesKt
-RemovedClass: androidx.compose.material3.Strings_androidKt:
-    Removed class androidx.compose.material3.Strings_androidKt
-RemovedClass: androidx.compose.material3.SwipeableKt:
-    Removed class androidx.compose.material3.SwipeableKt
-RemovedClass: androidx.compose.material3.SystemBarsDefaultInsets_androidKt:
-    Removed class androidx.compose.material3.SystemBarsDefaultInsets_androidKt
-RemovedClass: androidx.compose.material3.TextFieldDefaultsKt:
-    Removed class androidx.compose.material3.TextFieldDefaultsKt
-RemovedClass: androidx.compose.material3.TextFieldImplKt:
-    Removed class androidx.compose.material3.TextFieldImplKt
-RemovedClass: androidx.compose.material3.TonalPaletteKt:
-    Removed class androidx.compose.material3.TonalPaletteKt
-RemovedClass: androidx.compose.material3.TouchTargetKt:
-    Removed class androidx.compose.material3.TouchTargetKt
-RemovedClass: androidx.compose.material3.TypographyKt:
-    Removed class androidx.compose.material3.TypographyKt
-
-
-RemovedPackage: androidx.compose.material3.internal:
-    Removed package androidx.compose.material3.internal
+RemovedClass: androidx.compose.material3.TimePickerState:
+    Removed class androidx.compose.material3.TimePickerState
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index a0df8a5..0901450 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -826,22 +826,6 @@
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
   }
 
-  @androidx.compose.runtime.Stable public final class TimePickerState {
-    ctor public TimePickerState(int initialHour, int initialMinute, boolean is24Hour);
-    method public int getHour();
-    method public int getMinute();
-    method public boolean is24hour();
-    method public suspend Object? settle(kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final int hour;
-    property public final boolean is24hour;
-    property public final int minute;
-    field public static final androidx.compose.material3.TimePickerState.Companion Companion;
-  }
-
-  public static final class TimePickerState.Companion {
-    method public androidx.compose.runtime.saveable.Saver<androidx.compose.material3.TimePickerState,?> Saver();
-  }
-
   @androidx.compose.runtime.Immutable public final class Typography {
     ctor public Typography(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
     method public androidx.compose.material3.Typography copy(optional androidx.compose.ui.text.TextStyle displayLarge, optional androidx.compose.ui.text.TextStyle displayMedium, optional androidx.compose.ui.text.TextStyle displaySmall, optional androidx.compose.ui.text.TextStyle headlineLarge, optional androidx.compose.ui.text.TextStyle headlineMedium, optional androidx.compose.ui.text.TextStyle headlineSmall, optional androidx.compose.ui.text.TextStyle titleLarge, optional androidx.compose.ui.text.TextStyle titleMedium, optional androidx.compose.ui.text.TextStyle titleSmall, optional androidx.compose.ui.text.TextStyle bodyLarge, optional androidx.compose.ui.text.TextStyle bodyMedium, optional androidx.compose.ui.text.TextStyle bodySmall, optional androidx.compose.ui.text.TextStyle labelLarge, optional androidx.compose.ui.text.TextStyle labelMedium, optional androidx.compose.ui.text.TextStyle labelSmall);
diff --git a/compose/material3/material3/build.gradle b/compose/material3/material3/build.gradle
index a24036e..1624518 100644
--- a/compose/material3/material3/build.gradle
+++ b/compose/material3/material3/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -24,65 +25,86 @@
     id("AndroidXPaparazziPlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
+
+dependencies {
 
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+        implementation("androidx.activity:activity-compose:1.5.0")
+        implementation("androidx.compose.animation:animation-core:1.4.1")
+        implementation("androidx.compose.foundation:foundation-layout:1.4.1")
+        implementation("androidx.compose.ui:ui-util:1.4.1")
+        api("androidx.compose.foundation:foundation:1.4.1")
+        api("androidx.compose.material:material-icons-core:1.4.1")
+        api("androidx.compose.material:material-ripple:1.4.1")
+        api("androidx.compose.runtime:runtime:1.4.1")
+        api("androidx.compose.ui:ui-graphics:1.4.1")
+        api("androidx.compose.ui:ui:1.4.1")
+        api("androidx.compose.ui:ui-text:1.4.1")
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        // TODO: remove next 3 dependencies when b/202810604 is fixed
+        implementation("androidx.savedstate:savedstate-ktx:1.2.1")
+        implementation("androidx.lifecycle:lifecycle-runtime:2.6.1")
+        implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1")
+
+        implementation("androidx.lifecycle:lifecycle-common-java8:2.6.1")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:material3:material3:material3-samples"))
+        androidTestImplementation(project(":compose:foundation:foundation-layout"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":test:screenshot:screenshot"))
+        androidTestImplementation(project(":core:core"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.dexmakerMockitoInlineExtended)
+        androidTestImplementation(libs.mockitoKotlin)
+        androidTestImplementation(libs.testUiautomator)
+
+        lintPublish project(":compose:material3:material3-lint")
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                implementation("androidx.compose.animation:animation-core:1.4.0-beta02")
+                implementation(project(":compose:animation:animation-core"))
 
-                api("androidx.compose.foundation:foundation:1.4.0-beta02")
-                api("androidx.compose.material:material-icons-core:1.4.0-beta02")
-                api("androidx.compose.material:material-ripple:1.4.0-beta02")
-                api("androidx.compose.runtime:runtime:1.4.0-beta02")
-                api("androidx.compose.ui:ui-graphics:1.4.0-beta02")
-                api("androidx.compose.ui:ui-text:1.4.0-beta02")
+                api(project(":compose:foundation:foundation"))
+                api(project(":compose:material:material-icons-core"))
+                api(project(":compose:material:material-ripple"))
+                api(project(":compose:runtime:runtime"))
+                api(project(":compose:ui:ui-graphics"))
+                api(project(":compose:ui:ui-text"))
 
-                implementation("androidx.compose.ui:ui-util:1.4.0-beta02")
-                implementation("androidx.compose.foundation:foundation-layout:1.4.0-beta02")
-                implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
+                implementation(project(":compose:ui:ui-util"))
+                implementation(project(":compose:foundation:foundation-layout"))
             }
-        }
 
-        commonTest {
-            dependencies {
-
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    // unpinned dependencies for desktop
-                    implementation(project(":compose:animation:animation-core"))
-                    api(project(":compose:foundation:foundation"))
-                    api(project(":compose:material:material-icons-core"))
-                    api(project(":compose:material:material-ripple"))
-                    api(project(":compose:runtime:runtime"))
-                    api(project(":compose:ui:ui-graphics"))
-                    api(project(":compose:ui:ui-text"))
-                    implementation(project(":compose:ui:ui-util"))
-                    implementation(project(":compose:foundation:foundation-layout"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
                 implementation("androidx.activity:activity-compose:1.5.0")
 
@@ -93,32 +115,26 @@
 
                 implementation("androidx.lifecycle:lifecycle-common-java8:2.6.1")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:material3:material3:material3-samples"))
                 implementation(project(":compose:test-utils"))
-                implementation("androidx.compose.foundation:foundation-layout:1.4.0-beta02")
+                implementation(project(':compose:foundation:foundation-layout'))
                 implementation(project(":test:screenshot:screenshot"))
                 implementation(project(":core:core"))
                 implementation(libs.testRules)
@@ -130,31 +146,6 @@
                 implementation(libs.testUiautomator)
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-
-                }
-            }
-        }
     }
 }
 
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Components.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Components.kt
index 100d571..024eec6 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Components.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Components.kt
@@ -77,7 +77,7 @@
     // No bottom sheet icon
     guidelinesUrl = "$ComponentGuidelinesUrl/bottom-sheets",
     docsUrl = "$DocsUrl#bottomsheet",
-    sourceUrl = "$Material3SourceUrl/ModalBottomSheet.kt",
+    sourceUrl = "$Material3SourceUrl/ModalBottomSheet.android.kt",
     examples = BottomSheetExamples
 )
 
diff --git a/compose/material3/material3/samples/build.gradle b/compose/material3/material3/samples/build.gradle
index 35f4181..8a473aa 100644
--- a/compose/material3/material3/samples/build.gradle
+++ b/compose/material3/material3/samples/build.gradle
@@ -33,7 +33,7 @@
     implementation("androidx.activity:activity-compose:1.5.0")
     implementation("androidx.compose.animation:animation:1.2.1")
     implementation("androidx.compose.foundation:foundation:1.2.1")
-    implementation("androidx.compose.foundation:foundation-layout:1.4.0-beta02")
+    implementation("androidx.compose.foundation:foundation-layout:1.4.1")
     implementation("androidx.compose.material:material:1.2.1")
     implementation("androidx.compose.material:material-icons-extended:1.2.1")
     implementation(project(":compose:material3:material3"))
@@ -41,9 +41,9 @@
     implementation("androidx.compose.ui:ui:1.2.1")
     implementation("androidx.compose.ui:ui-text:1.2.1")
     implementation("androidx.savedstate:savedstate-ktx:1.2.1")
-    implementation("androidx.compose.ui:ui-tooling-preview:1.4.0-beta02")
+    implementation("androidx.compose.ui:ui-tooling-preview:1.4.1")
 
-    debugImplementation("androidx.compose.ui:ui-tooling:1.4.0-beta02")
+    debugImplementation("androidx.compose.ui:ui-tooling:1.4.1")
 }
 
 androidx {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/MaterialRippleThemeTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/MaterialRippleThemeTest.kt
index 5d55584..47fbfcb 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/MaterialRippleThemeTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/MaterialRippleThemeTest.kt
@@ -18,20 +18,20 @@
 
 import android.os.Build
 import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.interaction.DragInteraction
 import androidx.compose.foundation.Indication
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.HoverInteraction
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.PressInteraction
-import androidx.compose.foundation.indication
-import androidx.compose.foundation.interaction.FocusInteraction
-import androidx.compose.foundation.interaction.HoverInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.ripple.LocalRippleTheme
@@ -44,7 +44,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
-import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -62,7 +61,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
-import androidx.test.screenshot.AndroidXScreenshotTestRule
 import com.google.common.truth.Truth
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -76,15 +74,22 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@SdkSuppress(
+    // Below P the press ripple is split into two layers with half alpha, and we multiply the alpha
+    // first so each layer will have the expected alpha to ensure that the minimum contrast in
+    // areas where the ripples don't overlap is still correct - as a result the colors aren't
+    // exactly what we expect here so we can't really reliably assert
+    minSdkVersion = Build.VERSION_CODES.P,
+    // On S and above, the press ripple is patterned and has inconsistent behaviour in terms of
+    // alpha, so it doesn't behave according to our expectations - we can't explicitly assert on the
+    // color.
+    maxSdkVersion = Build.VERSION_CODES.R
+)
 class MaterialRippleThemeTest {
 
     @get:Rule
     val rule = createComposeRule()
 
-    @get:Rule
-    val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL3)
-
     @Test
     fun bounded_lightTheme_pressed() {
         val interactionSource = MutableInteractionSource()
@@ -102,7 +107,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_bounded_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -124,7 +128,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_bounded_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -146,7 +149,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_bounded_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -168,7 +170,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_bounded_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
     }
@@ -190,7 +191,6 @@
             scope,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_unbounded_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -212,7 +212,6 @@
             scope,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_unbounded_hovered",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
     }
@@ -234,7 +233,6 @@
             scope,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_unbounded_focused",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
     }
@@ -256,7 +254,6 @@
             scope,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_unbounded_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
     }
@@ -307,7 +304,6 @@
             scope!!,
             interactionSource,
             PressInteraction.Press(Offset(10f, 10f)),
-            "ripple_customtheme_pressed",
             expectedColor
         )
     }
@@ -358,7 +354,6 @@
             scope!!,
             interactionSource,
             HoverInteraction.Enter(),
-            "ripple_customtheme_hovered",
             expectedColor
         )
     }
@@ -409,7 +404,6 @@
             scope!!,
             interactionSource,
             FocusInteraction.Focus(),
-            "ripple_customtheme_focused",
             expectedColor
         )
     }
@@ -459,7 +453,6 @@
             scope!!,
             interactionSource,
             DragInteraction.Start(),
-            "ripple_customtheme_dragged",
             expectedColor
         )
     }
@@ -608,12 +601,10 @@
     }
 
     /**
-     * Asserts that the ripple matches the screenshot with identifier [goldenIdentifier], and
-     * that the resultant color of the ripple on screen matches [expectedCenterPixelColor].
+     * Asserts that the resultant color of the ripple on screen matches [expectedCenterPixelColor].
      *
      * @param interactionSource the [MutableInteractionSource] driving the ripple
      * @param interaction the [Interaction] to assert for
-     * @param goldenIdentifier the identifier for the corresponding screenshot
      * @param expectedCenterPixelColor the expected color for the pixel at the center of the
      * [RippleBoxWithBackground]
      */
@@ -621,7 +612,6 @@
         scope: CoroutineScope,
         interactionSource: MutableInteractionSource,
         interaction: Interaction,
-        goldenIdentifier: String,
         expectedCenterPixelColor: Color
     ) {
         // Pause the clock if we are drawing a state layer
@@ -646,14 +636,9 @@
             rule.mainClock.advanceTimeBy(milliseconds = 300)
         }
 
-        // Capture and compare screenshots
-        val screenshot = rule.onNodeWithTag(Tag)
-            .captureToImage()
-
-        screenshot.assertAgainstGolden(screenshotRule, goldenIdentifier)
-
         // Compare expected and actual pixel color
-        val centerPixel = screenshot
+        val centerPixel = rule.onNodeWithTag(Tag)
+            .captureToImage()
             .asAndroidBitmap()
             .run {
                 getPixel(width / 2, height / 2)
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ModalBottomSheet.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
similarity index 87%
rename from compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ModalBottomSheet.kt
rename to compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
index 2dae87c..33e9f0c 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ModalBottomSheet.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheet.android.kt
@@ -33,7 +33,6 @@
 import androidx.compose.foundation.layout.widthIn
 import androidx.compose.material3.SheetValue.Expanded
 import androidx.compose.material3.SheetValue.Hidden
-import androidx.compose.material3.SheetValue.PartiallyExpanded
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
@@ -54,6 +53,8 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
 import kotlin.math.max
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -197,7 +198,7 @@
                                         animateToDismiss()
                                         true
                                     }
-                                    if (currentValue == PartiallyExpanded) {
+                                    if (currentValue == SheetValue.PartiallyExpanded) {
                                         expand(expandActionLabel) {
                                             if (swipeableState.confirmValueChange(Expanded)) {
                                                 scope.launch { sheetState.expand() }
@@ -206,9 +207,9 @@
                                         }
                                     } else if (hasPartiallyExpandedState) {
                                         collapse(collapseActionLabel) {
-                                            if (
-                                                swipeableState.confirmValueChange(PartiallyExpanded)
-                                            ) {
+                                            val confirmPartial = swipeableState
+                                                .confirmValueChange(SheetValue.PartiallyExpanded)
+                                            if (confirmPartial) {
                                                 scope.launch { partialExpand() }
                                             }
                                             true
@@ -286,29 +287,29 @@
     bottomPadding: Float,
     onDragStopped: CoroutineScope.(velocity: Float) -> Unit,
 ) = draggable(
-            state = sheetState.swipeableState.swipeDraggableState,
-            orientation = Orientation.Vertical,
-            enabled = sheetState.isVisible,
-            startDragImmediately = sheetState.swipeableState.isAnimationRunning,
-            onDragStopped = onDragStopped
-        )
-        .swipeAnchors(
-            state = sheetState.swipeableState,
-            anchorChangeHandler = anchorChangeHandler,
-            possibleValues = setOf(Hidden, PartiallyExpanded, Expanded),
-        ) { value, sheetSize ->
-            when (value) {
-                Hidden -> screenHeight + bottomPadding
-                PartiallyExpanded -> when {
-                    sheetSize.height < screenHeight / 2 -> null
-                    sheetState.skipPartiallyExpanded -> null
-                    else -> screenHeight / 2f
-                }
-                Expanded -> if (sheetSize.height != 0) {
-                    max(0f, screenHeight - sheetSize.height)
-                } else null
+    state = sheetState.swipeableState.swipeDraggableState,
+    orientation = Orientation.Vertical,
+    enabled = sheetState.isVisible,
+    startDragImmediately = sheetState.swipeableState.isAnimationRunning,
+    onDragStopped = onDragStopped
+)
+    .swipeAnchors(
+        state = sheetState.swipeableState,
+        anchorChangeHandler = anchorChangeHandler,
+        possibleValues = setOf(Hidden, SheetValue.PartiallyExpanded, Expanded),
+    ) { value, sheetSize ->
+        when (value) {
+            Hidden -> screenHeight + bottomPadding
+            SheetValue.PartiallyExpanded -> when {
+                sheetSize.height < screenHeight / 2 -> null
+                sheetState.skipPartiallyExpanded -> null
+                else -> screenHeight / 2f
             }
+            Expanded -> if (sheetSize.height != 0) {
+                max(0f, screenHeight - sheetSize.height)
+            } else null
         }
+    }
 
 @ExperimentalMaterial3Api
 private fun ModalBottomSheetAnchorChangeHandler(
@@ -319,9 +320,9 @@
     val previousTargetOffset = previousAnchors[previousTarget]
     val newTarget = when (previousTarget) {
         Hidden -> Hidden
-        PartiallyExpanded, Expanded -> {
-            val hasPartiallyExpandedState = newAnchors.containsKey(PartiallyExpanded)
-            val newTarget = if (hasPartiallyExpandedState) PartiallyExpanded
+        SheetValue.PartiallyExpanded, Expanded -> {
+            val hasPartiallyExpandedState = newAnchors.containsKey(SheetValue.PartiallyExpanded)
+            val newTarget = if (hasPartiallyExpandedState) SheetValue.PartiallyExpanded
             else if (newAnchors.containsKey(Expanded)) Expanded else Hidden
             newTarget
         }
@@ -338,7 +339,16 @@
     }
 }
 
-internal expect fun ModalBottomSheetPopup(
+/**
+ * Popup specific for modal bottom sheet.
+ */
+@Composable
+@ExperimentalMaterial3Api
+internal fun ModalBottomSheetPopup(
     onDismissRequest: () -> Unit,
     content: @Composable () -> Unit
-)
+) = Popup(
+    onDismissRequest = onDismissRequest,
+    properties = PopupProperties(focusable = true),
+    content = content
+)
\ No newline at end of file
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.android.kt
deleted file mode 100644
index f2f2f09..0000000
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.android.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.material3
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.window.Popup
-import androidx.compose.ui.window.PopupProperties
-
-/**
- * Popup specific for modal bottom sheet.
- */
-@Composable
-@ExperimentalMaterial3Api
-internal actual fun ModalBottomSheetPopup(
-    onDismissRequest: () -> Unit,
-    content: @Composable () -> Unit
-) = Popup(
-    onDismissRequest = onDismissRequest,
-    properties = PopupProperties(focusable = true),
-    content = content
-)
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
index 04a642d..cd8bc57 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
@@ -488,6 +488,7 @@
  *  or `true` for 24 hour format without toggle.
  */
 @Stable
+@ExperimentalMaterial3Api
 class TimePickerState(
     initialHour: Int,
     initialMinute: Int,
diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.desktop.kt
deleted file mode 100644
index f45d210..0000000
--- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/ModalBottomSheetPopup.desktop.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.material3
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.window.Popup
-
-/**
- * Popup specific for modal bottom sheet.
- */
-@Composable
-@ExperimentalMaterial3Api
-internal actual fun ModalBottomSheetPopup(
-    onDismissRequest: () -> Unit,
-    content: @Composable () -> Unit
-) = Popup(content = content)
\ No newline at end of file
diff --git a/compose/runtime/runtime-livedata/build.gradle b/compose/runtime/runtime-livedata/build.gradle
index a496e2a..3dbc1e9 100644
--- a/compose/runtime/runtime-livedata/build.gradle
+++ b/compose/runtime/runtime-livedata/build.gradle
@@ -40,6 +40,8 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
+
+    samples(projectOrArtifact(":compose:runtime:runtime-livedata:runtime-livedata-samples"))
 }
 
 androidx {
diff --git a/compose/runtime/runtime-rxjava2/build.gradle b/compose/runtime/runtime-rxjava2/build.gradle
index f50f198..5b25d58 100644
--- a/compose/runtime/runtime-rxjava2/build.gradle
+++ b/compose/runtime/runtime-rxjava2/build.gradle
@@ -37,6 +37,8 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
+
+    samples(projectOrArtifact(":compose:runtime:runtime-rxjava2:runtime-rxjava2-samples"))
 }
 
 androidx {
diff --git a/compose/runtime/runtime-rxjava3/build.gradle b/compose/runtime/runtime-rxjava3/build.gradle
index f886326..6729b40 100644
--- a/compose/runtime/runtime-rxjava3/build.gradle
+++ b/compose/runtime/runtime-rxjava3/build.gradle
@@ -37,6 +37,8 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
+
+    samples(projectOrArtifact(":compose:runtime:runtime-rxjava3:runtime-rxjava3-samples"))
 }
 
 androidx {
diff --git a/compose/runtime/runtime-saveable/build.gradle b/compose/runtime/runtime-saveable/build.gradle
index 0aa2c68..b4d8073 100644
--- a/compose/runtime/runtime-saveable/build.gradle
+++ b/compose/runtime/runtime-saveable/build.gradle
@@ -15,8 +15,9 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -24,54 +25,77 @@
     id("com.android.library")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /* When updating dependencies, make sure to make the an an analogous update in the
+            corresponding block below */
+        api project(":compose:runtime:runtime")
+        api "androidx.annotation:annotation:1.1.0"
+
+        implementation(libs.kotlinStdlib)
+
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.testCore)
+        testImplementation(libs.testRules)
+
+        androidTestImplementation projectOrArtifact(':compose:ui:ui')
+        androidTestImplementation projectOrArtifact(":compose:ui:ui-test-junit4")
+        androidTestImplementation projectOrArtifact(":compose:test-utils")
+        androidTestImplementation "androidx.fragment:fragment:1.3.0"
+        androidTestImplementation projectOrArtifact(":activity:activity-compose")
+        androidTestImplementation(libs.testUiautomator)
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoCore)
+
+        lintPublish(project(":compose:runtime:runtime-saveable-lint"))
+
+        samples(projectOrArtifact(":compose:runtime:runtime-saveable:runtime-saveable-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /* When updating dependencies, make sure to make the an an analogous update in the
+            corresponding block above */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
                 api project(":compose:runtime:runtime")
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 implementation(libs.kotlinStdlib)
                 api "androidx.annotation:annotation:1.1.0"
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
-        }
 
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation project(':compose:ui:ui')
                 implementation project(":compose:ui:ui-test-junit4")
                 implementation project(":compose:test-utils")
@@ -88,31 +112,10 @@
                 implementation(libs.mockitoCore)
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
     }
-}
-
-dependencies {
-    lintPublish(project(":compose:runtime:runtime-saveable-lint"))
+    dependencies {
+        samples(projectOrArtifact(":compose:runtime:runtime-saveable:runtime-saveable-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/runtime/runtime/build.gradle b/compose/runtime/runtime/build.gradle
index 0d66c56..f7317d7 100644
--- a/compose/runtime/runtime/build.gradle
+++ b/compose/runtime/runtime/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,79 +24,87 @@
     id("com.android.library")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
-                implementation(libs.kotlinStdlibCommon)
-                implementation(libs.kotlinCoroutinesCore)
-            }
-        }
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-        commonTest {
-            dependencies {
-                implementation kotlin("test")
-                implementation(libs.kotlinCoroutinesTest)
-            }
-        }
+        api(libs.kotlinCoroutinesAndroid)
 
-        jvmMain {
-            dependencies {
-                implementation(libs.kotlinStdlib)
-                api(libs.kotlinCoroutinesCore)
-            }
-        }
+        implementation("androidx.annotation:annotation:1.1.0")
+        implementation(libs.kotlinStdlib)
 
+        testImplementation(libs.kotlinTestJunit)
+        testImplementation(libs.junit)
+        testImplementation(libs.robolectric)
+        testImplementation(libs.kotlinCoroutinesTest)
 
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                api(libs.kotlinCoroutinesAndroid)
-                api("androidx.annotation:annotation:1.1.0")
-            }
-        }
+        androidTestImplementation(libs.kotlinTestJunit)
+        androidTestImplementation(libs.testExtJunit)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-            }
-        }
+        lintChecks(projectOrArtifact(":compose:runtime:runtime-lint"))
+        lintPublish(projectOrArtifact(":compose:runtime:runtime-lint"))
 
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testExtJunit)
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.truth)
-            }
-        }
-
-        androidTest {
-            dependsOn(jvmTest)
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
+        samples(projectOrArtifact(":compose:runtime:runtime:runtime-samples"))
     }
 }
 
-dependencies {
-    lintChecks(projectOrArtifact(":compose:runtime:runtime-lint"))
-    lintPublish(projectOrArtifact(":compose:runtime:runtime-lint"))
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
+                implementation(libs.kotlinStdlibCommon)
+                implementation(libs.kotlinCoroutinesCore)
+            }
+            jvmMain.dependencies {
+                implementation(libs.kotlinStdlib)
+                api(libs.kotlinCoroutinesCore)
+            }
+            androidMain {
+                dependencies {
+                    api(libs.kotlinCoroutinesAndroid)
+                    api("androidx.annotation:annotation:1.1.0")
+                }
+            }
+
+            commonTest.dependencies {
+                implementation kotlin("test")
+                implementation(libs.kotlinCoroutinesTest)
+            }
+
+            androidAndroidTest {
+                dependsOn(jvmTest)
+                dependencies {
+                    implementation(libs.testExtJunit)
+                    implementation(libs.testRules)
+                    implementation(libs.testRunner)
+                    implementation(libs.truth)
+                }
+            }
+        }
+    }
+    dependencies {
+        samples(projectOrArtifact(":compose:runtime:runtime:runtime-samples"))
+    }
 }
 
 android {
diff --git a/compose/runtime/runtime/integration-tests/build.gradle b/compose/runtime/runtime/integration-tests/build.gradle
index 5ea4a0e..b9b65e5 100644
--- a/compose/runtime/runtime/integration-tests/build.gradle
+++ b/compose/runtime/runtime/integration-tests/build.gradle
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+
+import androidx.build.AndroidXComposePlugin
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
@@ -23,62 +24,69 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        androidTestImplementation(projectOrArtifact(":compose:ui:ui"))
+        androidTestImplementation(projectOrArtifact(":compose:material:material"))
+        androidTestImplementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(project(":compose:runtime:runtime"))
+        androidTestImplementation(projectOrArtifact(":compose:test-utils"))
+        androidTestImplementation(projectOrArtifact(":activity:activity-compose"))
+
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.kotlinTestJunit)
+        androidTestImplementation(libs.testExtJunit)
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.kotlinStdlib)
+        androidTestImplementation(libs.kotlinReflect)
+        androidTestImplementation(libs.truth)
+    }
+}
+
+android {
+    namespace "androidx.compose.runtime.integrationtests"
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 implementation(libs.kotlinCoroutinesCore)
                 implementation(projectOrArtifact(":compose:ui:ui"))
             }
-        }
-
-        commonTest {
-            dependencies {
-                implementation(kotlin("test-junit"))
-            }
-        }
-
-        jvmMain {
-            dependencies {
+            jvmMain.dependencies {
                 implementation(libs.kotlinStdlib)
                 api(libs.kotlinCoroutinesCore)
             }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api(libs.kotlinCoroutinesAndroid)
                 api("androidx.annotation:annotation:1.1.0")
 
                 implementation("androidx.core:core-ktx:1.1.0")
             }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    api(libs.kotlinCoroutinesSwing)
-                }
+            desktopMain.dependencies {
+                api(libs.kotlinCoroutinesSwing)
             }
-        }
 
-        jvmTest {
-            dependencies {
+            commonTest.dependencies {
+                implementation(kotlin("test-junit"))
             }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(projectOrArtifact(":compose:ui:ui"))
                 implementation(projectOrArtifact(":compose:material:material"))
                 implementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
@@ -90,23 +98,9 @@
                 implementation(libs.truth)
             }
         }
-
-        androidTest {
-            dependsOn(jvmTest)
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
     }
 }
 
-android {
-    namespace "androidx.compose.runtime.integrationtests"
-}
-
 tasks.withType(KotlinCompile).configureEach {
     kotlinOptions {
         incremental = false
diff --git a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
index 9eebe15..187595c 100644
--- a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
+++ b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
@@ -81,7 +81,7 @@
     uiThread {
         Choreographer.getInstance().postFrameCallback { latch.countDown() }
     }
-    assertTrue(latch.await(1, TimeUnit.HOURS), "Time-out waiting for choreographer frame")
+    assertTrue(latch.await(1, TimeUnit.MINUTES), "Time-out waiting for choreographer frame")
 }
 
 abstract class BaseComposeTest {
diff --git a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/LiveEditApiTests.kt b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/LiveEditApiTests.kt
index 549814d..b0e4d91 100644
--- a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/LiveEditApiTests.kt
+++ b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/LiveEditApiTests.kt
@@ -422,6 +422,36 @@
             assertThat(errors).hasSize(0)
         }
     }
+
+    @Test
+    @MediumTest
+    fun throwErrorOnReload_withNode() {
+        var shouldThrow = false
+        activity.show {
+            TestTextWError(text = "abc") { shouldThrow }
+        }
+
+        activity.waitForAFrame()
+
+        activityRule.runOnUiThread {
+            shouldThrow = true
+            simulateHotReload(Unit)
+
+            val start = textInvoked
+            var errors = compositionErrors()
+            assertThat(errors).hasSize(1)
+            assertThat(errors[0].first.message).isEqualTo("Text error!")
+            assertThat(errors[0].second).isEqualTo(true)
+
+            shouldThrow = false
+            invalidateGroup(errorKey) // wrong key, but composition should be retried regardless
+
+            assertTrue("TestTextWError should be invoked!", textInvoked > start)
+
+            errors = compositionErrors()
+            assertThat(errors).hasSize(0)
+        }
+    }
 }
 
 const val someFunctionKey = -1580285603 // Extracted from .class file
@@ -533,4 +563,16 @@
             error("Effect error!")
         }
     }
+}
+
+private var textInvoked = 0
+@Composable
+fun TestTextWError(text: String, shouldThrow: () -> Boolean = { true }) {
+    textInvoked++
+
+    Text(text)
+
+    if (shouldThrow()) {
+        error("Text error!")
+    }
 }
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
index 8040bef..243dc42 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
@@ -28,5 +28,5 @@
      * IMPORTANT: Whenever updating this value, please make sure to also update `versionTable` and
      * `minimumRuntimeVersionInt` in `VersionChecker.kt` of the compiler.
      */
-    const val version: Int = 9801
+    const val version: Int = 9901
 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 7df2c189..a8119e1 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -1477,6 +1477,7 @@
         if (!writer.closed) {
             writer.close()
         }
+        insertFixups.clear()
         createFreshInsertTable()
         compoundKeyHash = 0
         childrenComposing = 0
@@ -1485,6 +1486,7 @@
         reusing = false
         isComposing = false
         forciblyRecompose = false
+        reusingGroup = -1
     }
 
     internal fun changesApplied() {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
index cb4e9ee..77eeb588 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
@@ -623,7 +623,6 @@
                         }
                         applier.clear()
                         manager.dispatchRememberObservers()
-                        manager.dispatchNodeCallbacks()
                     }
                     manager.dispatchAbandons()
                 }
@@ -797,7 +796,6 @@
             writer.removeCurrentGroup(manager)
         }
         manager.dispatchRememberObservers()
-        manager.dispatchNodeCallbacks()
     }
 
     private fun applyChangesInLocked(changes: MutableList<Change>) {
@@ -822,7 +820,6 @@
             // that implement RememberObserver receive onRemembered before a side effect
             // that captured it and operates on it can run.
             manager.dispatchRememberObservers()
-            manager.dispatchNodeCallbacks()
             manager.dispatchSideEffects()
 
             if (pendingInvalidScopes) {
@@ -1102,6 +1099,18 @@
         }
 
         fun dispatchRememberObservers() {
+            // Send node deactivations
+            val deactivating = deactivating
+            if (!deactivating.isNullOrEmpty()) {
+                trace("Compose:deactivations") {
+                    for (i in deactivating.size - 1 downTo 0) {
+                        val instance = deactivating[i]
+                        instance.onDeactivate()
+                    }
+                }
+                deactivating.clear()
+            }
+
             // Send forgets
             if (forgetting.isNotEmpty()) {
                 trace("Compose:onForgotten") {
@@ -1123,6 +1132,20 @@
                     }
                 }
             }
+
+            // Send node releases
+            val releasing = releasing
+            if (!releasing.isNullOrEmpty()) {
+                // note that in contrast with objects from `forgetting` we will invoke the callback
+                // even for objects being abandoned.
+                trace("Compose:releases") {
+                    for (i in releasing.size - 1 downTo 0) {
+                        val instance = releasing[i]
+                        instance.onRelease()
+                    }
+                }
+                releasing.clear()
+            }
         }
 
         fun dispatchSideEffects() {
@@ -1148,32 +1171,6 @@
                 }
             }
         }
-
-        fun dispatchNodeCallbacks() {
-            val deactivating = deactivating
-            if (!deactivating.isNullOrEmpty()) {
-                trace("Compose:deactivations") {
-                    for (i in deactivating.size - 1 downTo 0) {
-                        val instance = deactivating[i]
-                        instance.onDeactivate()
-                    }
-                }
-                deactivating.clear()
-            }
-
-            val releasing = releasing
-            if (!releasing.isNullOrEmpty()) {
-                // note that in contrast with objects from `forgetting` we will invoke the callback
-                // even for objects being abandoned.
-                trace("Compose:releases") {
-                    for (i in releasing.size - 1 downTo 0) {
-                        val instance = releasing[i]
-                        instance.onRelease()
-                    }
-                }
-                releasing.clear()
-            }
-        }
     }
 }
 
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 02a9933..a304e5d 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
@@ -2187,7 +2187,11 @@
     fun moveFrom(table: SlotTable, index: Int, removeSourceGroup: Boolean = true): List<Anchor> {
         runtimeCheck(insertCount > 0)
 
-        if (index == 0 && currentGroup == 0 && this.table.groupsSize == 0) {
+        if (
+            index == 0 && currentGroup == 0 &&
+            this.table.groupsSize == 0 &&
+            table.groups.groupSize(index) == table.groupsSize
+        ) {
             // Special case for moving the entire slot table into an empty table. This case occurs
             // during initial composition.
             val myGroups = groups
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayIntMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayIntMap.kt
index 5644c62..69e32d6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayIntMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayIntMap.kt
@@ -19,11 +19,11 @@
 import androidx.compose.runtime.identityHashCode
 
 internal class IdentityArrayIntMap {
-    internal var size = 0
+    var size = 0
         private set
-    internal var keys: Array<Any?> = arrayOfNulls(4)
+    var keys: Array<Any?> = arrayOfNulls(4)
         private set
-    internal var values: IntArray = IntArray(4)
+    var values: IntArray = IntArray(4)
         private set
 
     operator fun get(key: Any): Int {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
index cb6d619..bc600cc 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
@@ -19,11 +19,11 @@
 import androidx.compose.runtime.identityHashCode
 
 internal class IdentityArrayMap<Key : Any, Value : Any?>(capacity: Int = 16) {
-    internal var keys = arrayOfNulls<Any?>(capacity)
+    var keys = arrayOfNulls<Any?>(capacity)
         private set
-    internal var values = arrayOfNulls<Any?>(capacity)
+    var values = arrayOfNulls<Any?>(capacity)
         private set
-    internal var size = 0
+    var size = 0
         private set
 
     fun isEmpty() = size == 0
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArraySet.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArraySet.kt
index 29721ca..1c250bd 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArraySet.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArraySet.kt
@@ -29,8 +29,7 @@
     override var size = 0
         private set
 
-    @PublishedApi
-    internal var values: Array<Any?> = arrayOfNulls(16)
+    var values: Array<Any?> = arrayOfNulls(16)
         private set
 
     /**
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityScopeMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityScopeMap.kt
index f94b85f..d683a23 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityScopeMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityScopeMap.kt
@@ -30,28 +30,27 @@
      * in the [IdentityScopeMap]. The length of the used values is [size], and all remaining values
      * are the unused indices in [values] and [scopeSets].
      */
-    @PublishedApi
-    internal var valueOrder: IntArray = IntArray(50) { it }
+    var valueOrder: IntArray = IntArray(50) { it }
+        private set
 
     /**
      * The [identityHashCode] for the keys in the collection. We never use the actual
      * values
      */
-    @PublishedApi
-    internal var values: Array<Any?> = arrayOfNulls(50)
+    var values: Array<Any?> = arrayOfNulls(50)
+        private set
 
     /**
      * The [IdentityArraySet]s for values, in the same index order as [values], indexed
      * by [valueOrder]. The consumed values may extend beyond [size] if a value has been removed.
      */
-    @PublishedApi
-    internal var scopeSets: Array<IdentityArraySet<T>?> = arrayOfNulls(50)
+    var scopeSets: Array<IdentityArraySet<T>?> = arrayOfNulls(50)
+        private set
 
     /**
      * The number of values in the map.
      */
-    @PublishedApi
-    internal var size = 0
+    var size = 0
 
     /**
      * Returns the [IdentityArraySet] for the value at the given [index] order in the map.
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index dd53854..06d1f47 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -23,11 +23,11 @@
 import androidx.compose.runtime.InternalComposeApi
 import androidx.compose.runtime.SnapshotThreadLocal
 import androidx.compose.runtime.collection.IdentityArraySet
+import androidx.compose.runtime.internal.JvmDefaultWithCompatibility
 import androidx.compose.runtime.synchronized
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.InvocationKind
 import kotlin.contracts.contract
-import androidx.compose.runtime.internal.JvmDefaultWithCompatibility
 
 /**
  * A snapshot of the values return by mutable states and other state objects. All state object
@@ -850,7 +850,7 @@
             // id to be forgotten as no state records will refer to it.
             this.modified = null
             val id = id
-            for (state in modified) {
+            modified.fastForEach { state ->
                 var current: StateRecord? = state.firstStateRecord
                 while (current != null) {
                     if (current.snapshotId == id || current.snapshotId in previousIds) {
@@ -885,12 +885,12 @@
         val start = this.invalid.set(id).or(this.previousIds)
         val modified = modified!!
         var statesToRemove: MutableList<StateObject>? = null
-        for (state in modified) {
+        modified.fastForEach { state ->
             val first = state.firstStateRecord
             // If either current or previous cannot be calculated the object was created
             // in a nested snapshot that was committed then changed.
-            val current = readable(first, snapshotId, invalidSnapshots) ?: continue
-            val previous = readable(first, id, start) ?: continue
+            val current = readable(first, snapshotId, invalidSnapshots) ?: return@fastForEach
+            val previous = readable(first, id, start) ?: return@fastForEach
             if (current != previous) {
                 val applied = readable(first, id, this.invalid) ?: readError()
                 val merged = optimisticMerges?.get(current) ?: run {
@@ -1403,12 +1403,12 @@
                 val result = innerApplyLocked(parent.id, optimisticMerges, parent.invalid)
                 if (result != SnapshotApplyResult.Success) return result
 
-                // Add all modified objects in this set to the parent
-                (
-                    parent.modified ?: IdentityArraySet<StateObject>().also {
+                parent.modified?.apply { addAll(modified) }
+                    ?: modified.also {
+                        // Ensure modified reference is only used by one snapshot
                         parent.modified = it
+                        this.modified = null
                     }
-                ).addAll(modified)
             }
 
             // Ensure the parent is newer than the current snapshot
@@ -2176,10 +2176,10 @@
     if (modified == null) return null
     val start = applyingSnapshot.invalid.set(applyingSnapshot.id).or(applyingSnapshot.previousIds)
     var result: MutableMap<StateRecord, StateRecord>? = null
-    for (state in modified) {
+    modified.fastForEach { state ->
         val first = state.firstStateRecord
-        val current = readable(first, id, invalidSnapshots) ?: continue
-        val previous = readable(first, id, start) ?: continue
+        val current = readable(first, id, invalidSnapshots) ?: return@fastForEach
+        val previous = readable(first, id, start) ?: return@fastForEach
         if (current != previous) {
             // Try to produce a merged state record
             val applied = readable(first, applyingSnapshot.id, applyingSnapshot.invalid)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
index cf562db..2ae56e8 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
@@ -106,8 +106,8 @@
 
     override fun addAll(elements: Collection<T>) = conditionalUpdate { it.addAll(elements) }
     override fun clear() {
-        synchronized(sync) {
-            writable {
+        writable {
+            synchronized(sync) {
                 list = persistentListOf()
                 modification++
             }
@@ -167,8 +167,8 @@
             val builder = oldList!!.builder()
             result = block(builder)
             val newList = builder.build()
-            if (newList == oldList || synchronized(sync) {
-                writable {
+            if (newList == oldList || writable {
+                 synchronized(sync) {
                     if (modification == currentModification) {
                         list = newList
                         modification++
@@ -201,8 +201,8 @@
                     result = false
                     break
                 }
-                if (synchronized(sync) {
-                    writable {
+                if (writable {
+                    synchronized(sync) {
                         if (modification == currentModification) {
                             list = newList
                             modification++
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
index aceccb7..9b77e7ce 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
@@ -137,8 +137,8 @@
             val builder = oldMap!!.builder()
             result = block(builder)
             val newMap = builder.build()
-            if (newMap == oldMap || synchronized(sync) {
-                writable {
+            if (newMap == oldMap || writable {
+                synchronized(sync) {
                     if (modification == currentModification) {
                         map = newMap
                         modification++
@@ -153,8 +153,8 @@
 
     private inline fun update(block: (PersistentMap<K, V>) -> PersistentMap<K, V>) = withCurrent {
         val newMap = block(map)
-        if (newMap !== map) synchronized(sync) {
-            writable {
+        if (newMap !== map) writable {
+            synchronized(sync) {
                 map = newMap
                 modification++
             }
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
index 16e0541..fcb9abc 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -631,6 +631,28 @@
     }
 
     @Test
+    fun testSkippingNestedLambda() = compositionTest {
+        val data = mutableStateOf(0)
+
+        itemRendererCalls = 0
+        scrollingListCalls = 0
+        compose {
+            TestSkippingContent(data = data)
+        }
+
+        data.value++
+        advance()
+
+        data.value++
+        advance()
+
+        data.value++
+        advance()
+
+        assertTrue(itemRendererCalls < scrollingListCalls)
+    }
+
+    @Test
     fun testComponentWithVarConstructorParameter() = compositionTest {
         @Composable
         fun One(first: Int) {
@@ -4058,4 +4080,57 @@
 ) = TestSubcomposition { content() }
 
 @Composable
-operator fun <T> CompositionLocal<T>.getValue(thisRef: Any?, property: KProperty<*>) = current
\ No newline at end of file
+operator fun <T> CompositionLocal<T>.getValue(thisRef: Any?, property: KProperty<*>) = current
+
+// for 274185312
+
+var itemRendererCalls = 0
+var scrollingListCalls = 0
+
+@Composable
+fun TestSkippingContent(data: State<Int>) {
+    ScrollingList { viewItem ->
+        Text("${data.value}")
+        scrollingListCalls++
+        ItemRenderer(viewItem)
+    }
+}
+
+@Composable
+fun ItemRenderer(viewItem: ListViewItem) {
+    itemRendererCalls++
+    Text("${viewItem.id}")
+}
+
+@Composable
+private fun ScrollingList(
+    itemRenderer: @Composable (ListViewItem) -> Unit,
+) {
+    ListContent(
+        viewItems = remember { listOf(ListViewItem(0), ListViewItem(1)) },
+        itemRenderer = itemRenderer
+    )
+}
+
+@Composable
+fun ListContent(
+    viewItems: List<ListViewItem>,
+    itemRenderer: @Composable (ListViewItem) -> Unit
+) {
+    viewItems.forEach { viewItem ->
+        ListContentItem(
+            viewItem = viewItem,
+            itemRenderer = itemRenderer
+        )
+    }
+}
+
+@Composable
+fun ListContentItem(
+    viewItem: ListViewItem,
+    itemRenderer: @Composable (ListViewItem) -> Unit
+) {
+    itemRenderer(viewItem)
+}
+
+data class ListViewItem(val id: Int)
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/SlotTableTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/SlotTableTests.kt
index a4b3600..d6505b04 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/SlotTableTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/SlotTableTests.kt
@@ -1401,6 +1401,56 @@
     }
 
     @Test
+    fun testMovingFromMultiRootGroup() {
+        val sourceTable = SlotTable()
+        val destinationTable = SlotTable()
+
+        val anchors = mutableListOf<Anchor>()
+        sourceTable.write { writer ->
+            writer.insert {
+                writer.group(10) {
+                    anchors.add(writer.anchor(writer.parent))
+                    writer.group(100) {
+                        writer.group(1000) { }
+                        writer.group(1001) { }
+                        writer.group(1002) { }
+                        writer.group(10003) { }
+                    }
+                }
+                writer.group(20) {
+                    anchors.add(writer.anchor(writer.parent))
+                    writer.group(200) {
+                        writer.group(2000) { }
+                        writer.group(2001) { }
+                        writer.group(2002) { }
+                        writer.group(20003) { }
+                    }
+                }
+                writer.group(30) {
+                    anchors.add(writer.anchor(writer.parent))
+                    writer.group(300) {
+                        writer.group(3000) { }
+                        writer.group(3001) { }
+                        writer.group(3002) { }
+                        writer.group(30003) { }
+                    }
+                }
+            }
+        }
+        sourceTable.verifyWellFormed()
+
+        destinationTable.write { writer ->
+            for (anchor in anchors) {
+                writer.insert {
+                    writer.moveFrom(sourceTable, sourceTable.anchorIndex(anchor))
+                    sourceTable.verifyWellFormed()
+                }
+            }
+        }
+        destinationTable.verifyWellFormed()
+    }
+
+    @Test
     fun testToIndexFor() {
         val (slots, anchors) = narrowTrees()
         val indexes = anchors.map { it.toIndexFor(slots) }
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
index d03fa3f..886b51c 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
@@ -27,6 +27,9 @@
 import kotlin.test.assertFailsWith
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.consumeEach
+import kotlinx.test.IgnoreJsTarget
 
 class SnapshotStateListTests {
     @Test
@@ -567,7 +570,9 @@
         }
     }
 
-    @Test @OptIn(ExperimentalCoroutinesApi::class)
+    @Test(timeout = 10_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
     fun concurrentGlobalModifications_addAll(): Unit = runTest {
         repeat(100) {
             val list = mutableStateListOf<Int>()
@@ -587,6 +592,104 @@
         }
     }
 
+    @Test(timeout = 30_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
+    fun concurrentMixingWriteApply_add(): Unit = runTest {
+        repeat(100) {
+            val lists = Array(100) { mutableStateListOf<Int>() }.toList()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            coroutineScope {
+                // Launch mutator
+                launch(Dispatchers.Default) {
+                    repeat(100) { index ->
+                        lists.fastForEach { list ->
+                            list.add(index)
+                        }
+
+                        // Simulate the write observer
+                        channel.trySend(Unit)
+                    }
+                    channel.close()
+                }
+
+                // Simulate the global snapshot manager
+                launch(Dispatchers.Default) {
+                    channel.consumeEach {
+                        Snapshot.notifyObjectsInitialized()
+                    }
+                }
+            }
+        }
+        // Should only get here if the above doesn't deadlock.
+    }
+
+    @Test(timeout = 30_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
+    fun concurrentMixingWriteApply_addAll_clear(): Unit = runTest {
+        repeat(10) {
+            val lists = Array(100) { mutableStateListOf<Int>() }.toList()
+            val data = Array(100) { index -> index }.toList()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            coroutineScope {
+                // Launch mutator
+                launch(Dispatchers.Default) {
+                    repeat(100) {
+                        lists.fastForEach { list ->
+                            list.addAll(data)
+                            list.clear()
+                        }
+                        // Simulate the write observer
+                        channel.trySend(Unit)
+                    }
+                    channel.close()
+                }
+
+                // Simulate the global snapshot manager
+                launch(Dispatchers.Default) {
+                    channel.consumeEach {
+                        Snapshot.notifyObjectsInitialized()
+                    }
+                }
+            }
+        }
+        // Should only get here if the above doesn't deadlock.
+    }
+
+    @Test(timeout = 30_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
+    fun concurrentMixingWriteApply_addAll_removeRange(): Unit = runTest {
+        repeat(4) {
+            val lists = Array(100) { mutableStateListOf<Int>() }.toList()
+            val data = Array(100) { index -> index }.toList()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            coroutineScope {
+                // Launch mutator
+                launch(Dispatchers.Default) {
+                    repeat(100) {
+                        lists.fastForEach { list ->
+                            list.addAll(data)
+                            list.removeRange(0, data.size)
+                        }
+                        // Simulate the write observer
+                        channel.trySend(Unit)
+                    }
+                    channel.close()
+                }
+
+                // Simulate the global snapshot manager
+                launch(Dispatchers.Default) {
+                    channel.consumeEach {
+                        Snapshot.notifyObjectsInitialized()
+                    }
+                }
+            }
+        }
+        // Should only get here if the above doesn't deadlock.
+    }
+
     @Test
     fun modificationAcrossSnapshots() {
         val list = mutableStateListOf<Int>()
@@ -628,8 +731,8 @@
 
     private fun <T> expected(expected: List<T>, actual: List<T>) {
         assertEquals(expected.size, actual.size)
-        (0 until expected.size).forEach {
+        expected.indices.forEach {
             assertEquals(expected[it], actual[it])
         }
     }
-}
\ No newline at end of file
+}
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
index 70d93d7..be1db36 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("ConvertArgumentToSet")
+
 package androidx.compose.runtime.snapshots
 
 import androidx.compose.runtime.mutableStateMapOf
@@ -27,6 +29,8 @@
 import kotlin.test.assertFailsWith
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.consumeEach
 import kotlinx.test.IgnoreJsTarget
 
 class SnapshotStateMapTests {
@@ -565,6 +569,71 @@
         }
     }
 
+    @Test(timeout = 30_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
+    fun concurrentMixingWriteApply_set(): Unit = runTest {
+        repeat(10) {
+            val maps = Array(100) { mutableStateMapOf<Int, Int>() }.toList()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            coroutineScope {
+                // Launch mutator
+                launch(Dispatchers.Default) {
+                    repeat(100) { index ->
+                        maps.fastForEach { map ->
+                            map[index] = index
+                        }
+
+                        // Simulate the write observer
+                        channel.trySend(Unit)
+                    }
+                    channel.close()
+                }
+
+                // Simulate the global snapshot manager
+                launch(Dispatchers.Default) {
+                    channel.consumeEach {
+                        Snapshot.notifyObjectsInitialized()
+                    }
+                }
+            }
+        }
+        // Should only get here if the above doesn't deadlock.
+    }
+
+    @Test(timeout = 30_000)
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @IgnoreJsTarget // Not relevant in a single threaded environment
+    fun concurrentMixingWriteApply_clear(): Unit = runTest {
+        repeat(10) {
+            val maps = Array(100) { mutableStateMapOf<Int, Int>() }.toList()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            coroutineScope {
+                // Launch mutator
+                launch(Dispatchers.Default) {
+                    repeat(100) {
+                        maps.fastForEach { map ->
+                            repeat(10) { index -> map[index] = index }
+                            map.clear()
+                        }
+
+                        // Simulate the write observer
+                        channel.trySend(Unit)
+                    }
+                    channel.close()
+                }
+
+                // Simulate the global snapshot manager
+                launch(Dispatchers.Default) {
+                    channel.consumeEach {
+                        Snapshot.notifyObjectsInitialized()
+                    }
+                }
+            }
+        }
+        // Should only get here if the above doesn't deadlock.
+    }
+
     private fun validateRead(
         initialMap: MutableMap<Int, Float> = defaultMap(),
         block: (Map<Int, Float>, Map<Int, Float>) -> Unit
diff --git a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.jvm.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.jvm.kt
index 172a413..d1772a9 100644
--- a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.jvm.kt
+++ b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.jvm.kt
@@ -23,6 +23,7 @@
 import androidx.compose.runtime.InternalComposeApi
 import androidx.compose.runtime.RecomposeScope
 import androidx.compose.runtime.Stable
+import androidx.compose.runtime.updateChangedFlags
 
 /**
  * A Restart is created to hold composable lambdas to track when they are invoked allowing
@@ -124,7 +125,9 @@
             c,
             dirty
         )
-        c.endRestartGroup()?.updateScope { nc, _ -> this(p1, nc, changed or 0b1) }
+        c.endRestartGroup()?.updateScope { nc, _ ->
+            this(p1, nc, updateChangedFlags(changed) or 0b1)
+        }
         return result
     }
 
@@ -138,7 +141,9 @@
             c,
             dirty
         )
-        c.endRestartGroup()?.updateScope { nc, _ -> this(p1, p2, nc, changed or 0b1) }
+        c.endRestartGroup()?.updateScope { nc, _ ->
+            this(p1, p2, nc, updateChangedFlags(changed) or 0b1)
+        }
         return result
     }
 
@@ -161,7 +166,9 @@
             c,
             dirty
         )
-        c.endRestartGroup()?.updateScope { nc, _ -> this(p1, p2, p3, nc, changed or 0b1) }
+        c.endRestartGroup()?.updateScope { nc, _ ->
+            this(p1, p2, p3, nc, updateChangedFlags(changed) or 0b1)
+        }
         return result
     }
 
@@ -194,7 +201,7 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, nc, changed or 0b1)
+            this(p1, p2, p3, p4, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -231,7 +238,7 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, nc, changed or 0b1)
+            this(p1, p2, p3, p4, p5, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -271,7 +278,7 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, nc, changed or 0b1)
+            this(p1, p2, p3, p4, p5, p6, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -283,7 +290,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         c: Composer,
         changed: Int
     ): Any? {
@@ -298,7 +305,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 c: Composer,
                 changed: Int
             ) -> Any?
@@ -309,12 +316,12 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             c,
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, nc, changed or 0b1)
+            this(p1, p2, p3, p4, p5, p6, param7, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -326,7 +333,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         c: Composer,
         changed: Int
@@ -342,7 +349,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 c: Composer,
                 changed: Int
@@ -354,13 +361,13 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             c,
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, p8, nc, changed or 0b1)
+            this(p1, p2, p3, p4, p5, p6, param7, p8, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -372,7 +379,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         c: Composer,
@@ -389,7 +396,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 c: Composer,
@@ -402,14 +409,14 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             c,
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, p8, p9, nc, changed or 0b1)
+            this(p1, p2, p3, p4, p5, p6, param7, p8, p9, nc, updateChangedFlags(changed) or 0b1)
         }
         return result
     }
@@ -421,7 +428,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -440,7 +447,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -455,7 +462,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -464,7 +471,7 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, nc, changed or 0b1, changed)
+            this(p1, p2, p3, p4, p5, p6, param7, p8, p9, p10, nc, changed or 0b1, changed)
         }
         return result
     }
@@ -476,7 +483,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -496,7 +503,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -512,7 +519,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -522,7 +529,20 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, nc, changed or 0b1, changed1)
+            this(
+                p1,
+                p2,
+                p3,
+                p4,
+                p5,
+                p6,
+                param7,
+                p8,
+                p9,
+                p10,
+                p11,
+                nc,
+                updateChangedFlags(changed) or 0b1, updateChangedFlags(changed1))
         }
         return result
     }
@@ -534,7 +554,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -555,7 +575,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -572,7 +592,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -583,7 +603,23 @@
             dirty
         )
         c.endRestartGroup()?.updateScope { nc, _ ->
-            this(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, nc, changed or 0b1, changed1)
+            this(
+                p1,
+                p2,
+                p3,
+                p4,
+                p5,
+                p6,
+                param7,
+                p8,
+                p9,
+                p10,
+                p11,
+                p12,
+                nc,
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
+            )
         }
         return result
     }
@@ -595,7 +631,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -617,7 +653,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -635,7 +671,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -654,7 +690,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -662,8 +698,8 @@
                 p12,
                 p13,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
@@ -676,7 +712,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -699,7 +735,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -718,7 +754,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -738,7 +774,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -747,8 +783,8 @@
                 p13,
                 p14,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
@@ -761,7 +797,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -785,7 +821,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -805,7 +841,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -826,7 +862,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -836,8 +872,8 @@
                 p14,
                 p15,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
@@ -850,7 +886,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -875,7 +911,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -896,7 +932,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -918,7 +954,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -929,8 +965,8 @@
                 p15,
                 p16,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
@@ -943,7 +979,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -969,7 +1005,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -991,7 +1027,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -1014,7 +1050,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -1026,8 +1062,8 @@
                 p16,
                 p17,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
@@ -1040,7 +1076,7 @@
         p4: Any?,
         p5: Any?,
         p6: Any?,
-        p7: Any?,
+        param7: Any?,
         p8: Any?,
         p9: Any?,
         p10: Any?,
@@ -1067,7 +1103,7 @@
                 p4: Any?,
                 p5: Any?,
                 p6: Any?,
-                p7: Any?,
+                param7: Any?,
                 p8: Any?,
                 p9: Any?,
                 p10: Any?,
@@ -1090,7 +1126,7 @@
             p4,
             p5,
             p6,
-            p7,
+            param7,
             p8,
             p9,
             p10,
@@ -1114,7 +1150,7 @@
                 p4,
                 p5,
                 p6,
-                p7,
+                param7,
                 p8,
                 p9,
                 p10,
@@ -1127,8 +1163,8 @@
                 p17,
                 p18,
                 nc,
-                changed or 0b1,
-                changed1
+                updateChangedFlags(changed) or 0b1,
+                updateChangedFlags(changed1)
             )
         }
         return result
diff --git a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
index 121e1e1..efaab94 100644
--- a/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
+++ b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.jvm.kt
@@ -22,6 +22,7 @@
 import androidx.compose.runtime.InternalComposeApi
 import androidx.compose.runtime.RecomposeScope
 import androidx.compose.runtime.Stable
+import androidx.compose.runtime.updateChangedFlags
 import kotlin.jvm.functions.FunctionN
 
 @Stable
@@ -120,8 +121,10 @@
         c.endRestartGroup()?.updateScope { nc, _ ->
             val params = args.slice(0 until realParams).toTypedArray()
             @Suppress("UNUSED_VARIABLE")
-            val changed = args[realParams + 1] as Int
-            val changedN = args.slice(realParams + 2 until args.size).toTypedArray()
+            val changed = updateChangedFlags(args[realParams + 1] as Int)
+            val changedN = Array<Any?>(args.size - realParams - 2) { index ->
+                updateChangedFlags(args[realParams + 2 + index] as Int)
+            }
             this(
                 *params,
                 nc,
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index db014b4..5b5d26c 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
 import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,96 +25,89 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = false // b/276387374 TODO: KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+
+        api("androidx.activity:activity:1.2.0")
+        api(projectOrArtifact(":compose:ui:ui-test-junit4"))
+        api(project(":test:screenshot:screenshot"))
+
+        implementation(libs.kotlinStdlibCommon)
+        implementation(projectOrArtifact(":compose:runtime:runtime"))
+        implementation(projectOrArtifact(":compose:ui:ui-unit"))
+        implementation(projectOrArtifact(":compose:ui:ui-graphics"))
+        implementation("androidx.activity:activity-compose:1.3.1")
+        // old version of common-java8 conflicts with newer version, because both have
+        // DefaultLifecycleEventObserver.
+        // Outside of androidx this is resolved via constraint added to lifecycle-common,
+        // but it doesn't work in androidx.
+        // See aosp/1804059
+        implementation("androidx.lifecycle:lifecycle-common-java8:2.5.1")
+        implementation(libs.testCore)
+        implementation(libs.testRules)
+
+        // This has stub APIs for access to legacy Android APIs, so we don't want
+        // any dependency on this module.
+        compileOnly(projectOrArtifact(":compose:ui:ui-android-stubs"))
+
+        testImplementation(libs.truth)
+
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(projectOrArtifact(":compose:material:material"))
+    }
+}
+
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 implementation(projectOrArtifact(":compose:runtime:runtime"))
                 implementation(projectOrArtifact(":compose:ui:ui-unit"))
                 implementation(projectOrArtifact(":compose:ui:ui-graphics"))
                 implementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
             }
-        }
-        androidMain.dependencies {
-            api("androidx.activity:activity:1.2.0")
-            implementation "androidx.activity:activity-compose:1.3.1"
-            api(projectOrArtifact(":compose:ui:ui-test-junit4"))
-            api(project(":test:screenshot:screenshot"))
-            // This has stub APIs for access to legacy Android APIs, so we don't want
-            // any dependency on this module.
-            compileOnly(projectOrArtifact(":compose:ui:ui-android-stubs"))
-            implementation(libs.testCore)
-            implementation(libs.testRules)
-        }
 
-        commonTest {
-            dependencies {
+            androidMain.dependencies {
+                api("androidx.activity:activity:1.2.0")
+                implementation "androidx.activity:activity-compose:1.3.1"
+                api(projectOrArtifact(":compose:ui:ui-test-junit4"))
+                api(project(":test:screenshot:screenshot"))
+                // This has stub APIs for access to legacy Android APIs, so we don't want
+                // any dependency on this module.
+                compileOnly(projectOrArtifact(":compose:ui:ui-android-stubs"))
+                implementation(libs.testCore)
+                implementation(libs.testRules)
             }
-        }
 
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.truth)
             }
-        }
 
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(libs.truth)
                 implementation(projectOrArtifact(":compose:material:material"))
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
-            }
-        }
     }
 }
 
diff --git a/compose/ui/ui-geometry/build.gradle b/compose/ui/ui-geometry/build.gradle
index 15e6e16..1a05daf 100644
--- a/compose/ui/ui-geometry/build.gradle
+++ b/compose/ui/ui-geometry/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,69 +24,53 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api("androidx.annotation:annotation:1.1.0")
+
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation(project(":compose:ui:ui-util"))
+        implementation(libs.kotlinStdlib)
+
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.kotlinTest)
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
-                implementation("androidx.compose.runtime:runtime:1.2.1")
+                implementation(project(":compose:runtime:runtime"))
                 implementation(project(":compose:ui:ui-util"))
             }
-        }
-
-        commonTest {
-            dependencies {
-                implementation(kotlin("test-junit"))
-            }
-        }
-
-        jvmMain {
-            dependencies {
+            jvmMain.dependencies {
                 implementation(libs.kotlinStdlib)
             }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
             }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(project(":compose:runtime:runtime"))
-                }
-            }
-        }
-
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
-            }
-        }
-
-        androidTest {
-            dependsOn(jvmTest)
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
+            commonTest.dependencies {
+                implementation(kotlin("test-junit"))
             }
         }
     }
diff --git a/compose/ui/ui-graphics/build.gradle b/compose/ui/ui-graphics/build.gradle
index 8583214..815c1df 100644
--- a/compose/ui/ui-graphics/build.gradle
+++ b/compose/ui/ui-graphics/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,71 +24,102 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api("androidx.annotation:annotation:1.2.0")
+        api(project(":compose:ui:ui-unit"))
+
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation(project(":compose:ui:ui-util"))
+        implementation(libs.kotlinStdlibCommon)
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.kotlinTestJunit)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(project(":compose:ui:ui-graphics:ui-graphics-samples"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+
+        lintPublish(project(":compose:ui:ui-graphics-lint"))
+
+        samples(projectOrArtifact(":compose:ui:ui-graphics:ui-graphics-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
 
                 api(project(":compose:ui:ui-unit"))
-                implementation("androidx.compose.runtime:runtime:1.2.1")
+                implementation(project(":compose:runtime:runtime"))
                 implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
-                implementation(kotlin("test"))
+            androidMain.dependencies {
+                api("androidx.annotation:annotation:1.2.0")
             }
-        }
 
-        if (desktopEnabled) {
             skikoMain {
                 dependsOn(commonMain)
                 dependencies {
                     api(libs.skikoCommon)
-                    implementation(project(":compose:runtime:runtime"))
                 }
             }
-        }
 
-        jvmMain {
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                api("androidx.annotation:annotation:1.2.0")
-            }
-        }
-
-        if (desktopEnabled) {
             desktopMain {
-                dependsOn(jvmMain)
-                dependsOn(skikoMain)
+                dependsOn skikoMain
                 dependencies {
                     implementation(libs.kotlinStdlib)
                     implementation(libs.kotlinStdlibJdk8)
                 }
             }
-        }
 
-        jvmTest {
-            dependencies {
+            commonTest {
+                dependencies {
+                    implementation(kotlin("test"))
+                }
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
+            }
+
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:ui:ui-graphics:ui-graphics-samples"))
                 implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":compose:test-utils"))
@@ -96,26 +128,9 @@
                 implementation(libs.espressoCore)
                 implementation(libs.junit)
             }
-        }
 
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
             desktopTest {
                 resources.srcDirs += "src/desktopTest/res"
-                dependsOn(jvmTest)
                 dependencies {
                     implementation(project(":compose:ui:ui-test-junit4"))
                     implementation(libs.junit)
@@ -125,10 +140,9 @@
             }
         }
     }
-}
-
-dependencies {
-    lintPublish(project(":compose:ui:ui-graphics-lint"))
+    dependencies {
+        samples(projectOrArtifact(":compose:ui:ui-graphics:ui-graphics-samples"))
+    }
 }
 
 androidx {
@@ -147,7 +161,7 @@
     namespace "androidx.compose.ui.graphics"
 }
 
-if (desktopEnabled) {
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
     tasks.findByName("desktopTest").configure {
         systemProperties["GOLDEN_PATH"] = project.rootDir.absolutePath + "/../../golden"
     }
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Canvas.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Canvas.kt
index 79ef583..9dd8132 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Canvas.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Canvas.kt
@@ -328,6 +328,7 @@
      * @param top Top bound of the clip region
      * @param right Right bound of the clip region
      * @param bottom Bottom bound of the clip region
+     * @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
      */
     fun clipRect(
         left: Float,
@@ -477,6 +478,7 @@
      * @param startAngle Starting angle of the arc relative to 3 o'clock
      * @param sweepAngle Sweep angle in degrees clockwise
      * @param useCenter Flag indicating whether or not to include the center of the oval in the
+     * @param paint Paint used to draw the arc.
      * arc, and close it if it is being stroked. This will draw a wedge.
      */
     fun drawArc(
diff --git a/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/vector/FastFloatParserTest.kt b/compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/vector/FastFloatParser.kt
similarity index 100%
rename from compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/vector/FastFloatParserTest.kt
rename to compose/ui/ui-graphics/src/commonTest/kotlin/androidx/compose/ui/graphics/vector/FastFloatParser.kt
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
index ef0fb76..b03678a6 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopImageConverters.desktop.kt
@@ -83,6 +83,8 @@
  * [density] also will be used to rasterize the default image, which can be used by some implementations
  * (Tray icon on macOs, disabled icon for menu items)
  *
+ * @param density density will be used to convert [dp] units
+ * @param layoutDirection direction for layout when drawing
  * @param size the size of the [Image]
  */
 @Deprecated(
@@ -106,6 +108,8 @@
  * they don't use absolute '.dp' values to draw, they use values which are relative
  * to their viewport.
  *
+ * @param density density will be used to convert [dp] units when drawing
+ * @param layoutDirection direction for layout when drawing
  * @param size the size of the [Image]
  */
 fun Painter.toAwtImage(
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/DialogTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/DialogTest.kt
index f0e401e..07d9416 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/DialogTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/DialogTest.kt
@@ -29,6 +29,7 @@
 import kotlinx.coroutines.runBlocking
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.ComposableNode
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetComposablesResponse
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 
@@ -37,6 +38,7 @@
     @get:Rule
     val rule = ComposeInspectionRule(DialogTestActivity::class)
 
+    @Ignore // b/273151077
     @Test
     fun dialogLocation(): Unit = runBlocking {
         assertThat(rule.roots).hasSize(2)
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
index a24934d..f78d114 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
@@ -97,6 +97,7 @@
 import kotlin.math.roundToInt
 import org.junit.After
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -164,6 +165,7 @@
         assertThat(DEBUG).isFalse()
     }
 
+    @Ignore // b/273151077
     @Test
     fun buildTree() {
         val slotTableRecord = CompositionDataRecord.create()
@@ -244,6 +246,7 @@
         }
     }
 
+    @Ignore // b/273151077
     @Test
     fun buildTreeWithTransformedText() {
         val slotTableRecord = CompositionDataRecord.create()
@@ -465,6 +468,7 @@
         assertThat(node?.id).isGreaterThan(0)
     }
 
+    @Ignore // b/273151077
     @Test
     fun testSemantics() {
         val slotTableRecord = CompositionDataRecord.create()
@@ -517,6 +521,7 @@
         }
     }
 
+    @Ignore // b/273151077
     @Test
     fun testDialog() {
         val slotTableRecord = CompositionDataRecord.create()
@@ -589,6 +594,7 @@
         }
     }
 
+    @Ignore // b/273151077
     @Test
     fun testPopup() {
         val slotTableRecord = CompositionDataRecord.create()
@@ -820,6 +826,7 @@
     }
     // WARNING: End formatted section
 
+    @Ignore // b/273151077
     @Test
     fun testLineNumbers() {
         // WARNING: The formatting of the lines below here affect test results.
@@ -905,9 +912,10 @@
         val cross1 = tree1.flatMap { flatten(it) }.single { it.name == "Crossfade" }
         val button1 = tree1.flatMap { flatten(it) }.single { it.name == "Button" }
         val column1 = tree1.flatMap { flatten(it) }.single { it.name == "Column" }
-        assertThat(cross1.id < RESERVED_FOR_GENERATED_IDS)
-        assertThat(button1.id < RESERVED_FOR_GENERATED_IDS)
-        assertThat(column1.id < RESERVED_FOR_GENERATED_IDS)
+
+        assertThat(cross1.id).isGreaterThan(RESERVED_FOR_GENERATED_IDS)
+        assertThat(button1.id).isGreaterThan(RESERVED_FOR_GENERATED_IDS)
+        assertThat(column1.id).isLessThan(RESERVED_FOR_GENERATED_IDS)
 
         composeTestRule.onNodeWithText("Button").performClick()
         composeTestRule.runOnIdle {
@@ -920,7 +928,7 @@
             val cross2 = tree2.flatMap { flatten(it) }.first { it.name == "Crossfade" }
             val button2 = tree2.flatMap { flatten(it) }.single { it.name == "Button" }
             val column2 = tree2.flatMap { flatten(it) }.single { it.name == "Column" }
-            assertThat(cross2.id).isEqualTo(cross1.id)
+            assertThat(cross2.id).isNotEqualTo(cross1.id)
             assertThat(button2.id).isEqualTo(button1.id)
             assertThat(column2.id).isEqualTo(column1.id)
         }
diff --git a/compose/ui/ui-test-junit4/build.gradle b/compose/ui/ui-test-junit4/build.gradle
index 3889b55..5e4501d 100644
--- a/compose/ui/ui-test-junit4/build.gradle
+++ b/compose/ui/ui-test-junit4/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,74 +24,107 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+android {
+    lintOptions {
+        disable("InvalidPackage")
+    }
+    namespace "androidx.compose.ui.test.junit4"
+}
 
-    sourceSets {
-        commonMain {
-            dependencies {
+dependencies {
+
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        api(project(":compose:ui:ui-test"))
+        api("androidx.activity:activity:1.2.1")
+        api(libs.junit)
+        api(libs.kotlinStdlib)
+        api(libs.kotlinStdlibCommon)
+        api(libs.testExtJunit)
+
+        implementation("androidx.compose.runtime:runtime-saveable:1.2.1")
+        implementation("androidx.activity:activity-compose:1.3.0")
+        implementation("androidx.annotation:annotation:1.1.0")
+        implementation("androidx.lifecycle:lifecycle-common:2.5.1")
+        implementation("androidx.lifecycle:lifecycle-runtime:2.5.1")
+        implementation("androidx.test:core:1.5.0")
+        implementation("androidx.test:monitor:1.6.0")
+        implementation("androidx.test.espresso:espresso-core:3.5.0")
+        implementation("androidx.test.espresso:espresso-idling-resource:3.5.0")
+        implementation(libs.kotlinCoroutinesCore)
+        implementation(libs.kotlinCoroutinesTest)
+
+        testImplementation(project(":compose:animation:animation-core"))
+        testImplementation(project(":compose:material:material"))
+        testImplementation(project(":compose:test-utils"))
+        testImplementation(libs.truth)
+        testImplementation(libs.robolectric)
+
+        androidTestImplementation(project(":compose:animation:animation"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation("androidx.fragment:fragment-testing:1.4.1")
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoKotlin)
+    }
+}
+
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        sourceSets {
+            commonMain.dependencies {
                 api(project(":compose:ui:ui-test"))
                 implementation(libs.kotlinStdlib)
                 implementation(libs.kotlinCoroutinesCore)
                 implementation(libs.kotlinCoroutinesTest)
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
+            jvmMain.dependencies {
                 api(libs.junit)
                 api(libs.kotlinStdlib)
                 api(libs.kotlinStdlibCommon)
 
                 compileOnly("androidx.annotation:annotation:1.1.0")
             }
-        }
 
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.activity:activity:1.2.1")
                 implementation "androidx.activity:activity-compose:1.3.0"
                 api(libs.testExtJunit)
                 implementation("androidx.annotation:annotation:1.1.0")
 
-                implementation("androidx.compose.runtime:runtime-saveable:1.2.1")
+                implementation(project(":compose:runtime:runtime-saveable"))
                 implementation("androidx.lifecycle:lifecycle-common:2.5.1")
                 implementation("androidx.lifecycle:lifecycle-runtime:2.5.1")
-                implementation("androidx.test:core:1.5.0")
+                implementation("androidx.test:core:1.4.0")
                 implementation(libs.testMonitor)
                 implementation("androidx.test.espresso:espresso-core:3.3.0")
-                implementation("androidx.test.espresso:espresso-idling-resource:3.5.0")
+                implementation("androidx.test.espresso:espresso-idling-resource:3.3.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.truth)
-                    implementation(libs.skiko)
-                }
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(project(":compose:animation:animation-core"))
+                implementation(project(":compose:material:material"))
+                implementation(project(":compose:test-utils"))
+                implementation(libs.truth)
             }
-        }
 
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:animation:animation"))
                 implementation(project(":compose:test-utils"))
                 implementation(project(":compose:material:material"))
@@ -102,50 +136,28 @@
                 implementation(libs.dexmakerMockito)
                 implementation(libs.mockitoKotlin)
             }
-        }
 
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(project(":compose:animation:animation-core"))
-                implementation(project(":compose:material:material"))
-                implementation(project(":compose:test-utils"))
+            desktopMain.dependencies {
                 implementation(libs.truth)
+                implementation(libs.skiko)
             }
-        }
 
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependencies {
-                    implementation(libs.truth)
-                    implementation(libs.junit)
-                    implementation(libs.kotlinTest)
-                    implementation(libs.skikoCurrentOs)
-                    implementation(project(":compose:foundation:foundation"))
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                }
+            desktopTest.dependencies {
+                implementation(libs.truth)
+                implementation(libs.junit)
+                implementation(libs.kotlinTest)
+                implementation(libs.skikoCurrentOs)
+                implementation(project(":compose:foundation:foundation"))
+                implementation(project(":compose:ui:ui-test-junit4"))
             }
         }
     }
-}
 
-
-android {
-    lintOptions {
-        disable("InvalidPackage")
+    dependencies {
+        // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
+        // leaks into instrumented tests (b/214407011)
+        testImplementation(libs.robolectric)
     }
-    namespace "androidx.compose.ui.test.junit4"
-}
-
-dependencies {
-    // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
-    // leaks into instrumented tests (b/214407011)
-    testImplementation(libs.robolectric)
 }
 
 androidx {
diff --git a/compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt b/compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt
index a88b849..606882a 100644
--- a/compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt
+++ b/compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt
@@ -19,6 +19,7 @@
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -29,6 +30,7 @@
     @get:Rule
     val rule = createComposeRule()
 
+    @Ignore("b/276935528")
     @Test
     fun test() {
         rule.setContent {}
diff --git a/compose/ui/ui-test/api/current.ignore b/compose/ui/ui-test/api/current.ignore
new file mode 100644
index 0000000..6cf936b
--- /dev/null
+++ b/compose/ui/ui-test/api/current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
+    Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
+ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
+    Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
+
+
+RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
+    Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>,kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>)
+RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
+    Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>)
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 2c691fc..684e9c8 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -11,8 +11,8 @@
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performScrollToNode(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.test.SemanticsMatcher matcher);
     method public static <T extends kotlin.Function<? extends java.lang.Boolean>> androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> invocation);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> key);
-    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
-    method @Deprecated public static void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
+    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
+    method @Deprecated public static void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performTouchInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.TouchInjectionScope,kotlin.Unit> block);
   }
 
diff --git a/compose/ui/ui-test/api/public_plus_experimental_current.txt b/compose/ui/ui-test/api/public_plus_experimental_current.txt
index 7e23701..219da1d 100644
--- a/compose/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-test/api/public_plus_experimental_current.txt
@@ -14,8 +14,8 @@
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performScrollToNode(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.test.SemanticsMatcher matcher);
     method public static <T extends kotlin.Function<? extends java.lang.Boolean>> androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> invocation);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> key);
-    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
-    method @Deprecated public static void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
+    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
+    method @Deprecated public static void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performTouchInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.TouchInjectionScope,kotlin.Unit> block);
   }
 
diff --git a/compose/ui/ui-test/api/restricted_current.ignore b/compose/ui/ui-test/api/restricted_current.ignore
new file mode 100644
index 0000000..6cf936b
--- /dev/null
+++ b/compose/ui/ui-test/api/restricted_current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
+    Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
+ChangedType: androidx.compose.ui.test.ActionsKt#performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
+    Method androidx.compose.ui.test.ActionsKt.performSemanticsAction has changed return type from androidx.compose.ui.test.SemanticsNodeInteraction to void
+
+
+RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>):
+    Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>>,kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit>)
+RemovedDeprecatedMethod: androidx.compose.ui.test.ActionsKt#performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>):
+    Removed deprecated method androidx.compose.ui.test.ActionsKt.performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction,androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>>)
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index 2b72c5f..1305308 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -11,8 +11,8 @@
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performScrollToNode(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.test.SemanticsMatcher matcher);
     method public static <T extends kotlin.Function<? extends java.lang.Boolean>> androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> invocation);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<java.lang.Boolean>>> key);
-    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
-    method @Deprecated public static void performSemanticsActionUnit(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
+    method @Deprecated public static <T extends kotlin.Function<? extends java.lang.Boolean>> void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<T>> key, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> invocation);
+    method @Deprecated public static void performSemanticsAction(androidx.compose.ui.test.SemanticsNodeInteraction, androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityAction<kotlin.jvm.functions.Function0<? extends java.lang.Boolean>>> key);
     method public static androidx.compose.ui.test.SemanticsNodeInteraction performTouchInput(androidx.compose.ui.test.SemanticsNodeInteraction, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.TouchInjectionScope,kotlin.Unit> block);
   }
 
diff --git a/compose/ui/ui-test/build.gradle b/compose/ui/ui-test/build.gradle
index d5afe32..097486a 100644
--- a/compose/ui/ui-test/build.gradle
+++ b/compose/ui/ui-test/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,115 +24,14 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
-
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
-
-    sourceSets {
-        commonMain {
-            dependencies {
-                api(project(":compose:ui:ui"))
-                api(project(":compose:ui:ui-text"))
-                api(project(":compose:ui:ui-unit"))
-                api(libs.kotlinStdlib)
-
-                implementation(project(":compose:ui:ui-util"))
-            }
-        }
-
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-                api("androidx.compose.runtime:runtime:1.2.1")
-                api(libs.kotlinCoroutinesCore)
-                api(libs.kotlinCoroutinesTest)
-                api(libs.kotlinStdlibCommon)
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                api(project(":compose:ui:ui-graphics"))
-
-                implementation("androidx.annotation:annotation:1.1.0")
-                implementation("androidx.core:core-ktx:1.2.0")
-                implementation("androidx.test.espresso:espresso-core:3.5.0")
-                implementation(libs.testMonitor)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.junit)
-                    implementation(libs.truth)
-                    implementation(libs.skiko)
-                    api(project(":compose:runtime:runtime"))
-                }
-            }
-        }
-
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidCommonTest {
-            dependsOn(commonTest)
-            dependencies {
-                implementation(project(":compose:test-utils"))
-                implementation(libs.truth)
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidCommonTest)
-            dependencies {
-                implementation(project(":compose:material:material"))
-                implementation(project(":compose:ui:ui-test-junit4"))
-                implementation("androidx.activity:activity-compose:1.3.1")
-                implementation(libs.mockitoCore)
-                implementation(libs.mockitoKotlin)
-                implementation(libs.dexmakerMockito)
-                implementation(libs.kotlinTest)
-            }
-        }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidCommonTest)
-            dependencies {
-                implementation(libs.mockitoCore4)
-                implementation(libs.mockitoKotlin4)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
-    }
-}
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
 android {
-    sourceSets {
-        test.java.srcDirs += "src/androidCommonTest/kotlin"
-        androidTest.java.srcDirs += "src/androidCommonTest/kotlin"
+    if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        sourceSets {
+            test.java.srcDirs += "src/androidCommonTest/kotlin"
+            androidTest.java.srcDirs += "src/androidCommonTest/kotlin"
+        }
     }
 
     lintOptions {
@@ -141,9 +41,121 @@
 }
 
 dependencies {
-    // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
-    // leaks into instrumented tests (b/214407011)
-    testImplementation(libs.robolectric)
+
+    if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api(project(":compose:ui:ui"))
+        api(project(":compose:ui:ui-graphics"))
+        api(project(":compose:ui:ui-text"))
+        api(project(":compose:ui:ui-unit"))
+        api(libs.kotlinCoroutinesCore)
+        api(libs.kotlinCoroutinesTest)
+        api(libs.kotlinStdlib)
+        api(libs.kotlinStdlibCommon)
+
+        implementation(project(":compose:ui:ui-util"))
+        implementation("androidx.annotation:annotation:1.1.0")
+        implementation("androidx.core:core-ktx:1.1.0")
+        implementation("androidx.test.espresso:espresso-core:3.5.0")
+        implementation("androidx.test:monitor:1.6.0")
+
+        testImplementation(project(":compose:test-utils"))
+        testImplementation(libs.truth)
+        testImplementation(libs.robolectric)
+        testImplementation(libs.mockitoCore4)
+        testImplementation(libs.mockitoKotlin4)
+
+        androidTestImplementation("androidx.activity:activity-compose:1.3.1")
+        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoKotlin)
+        androidTestImplementation(libs.kotlinTest)
+
+        samples(project(":compose:ui:ui-test:ui-test-samples"))
+    }
+}
+
+
+if (AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        sourceSets {
+            commonMain.dependencies {
+                api(project(":compose:ui:ui"))
+                api(project(":compose:ui:ui-text"))
+                api(project(":compose:ui:ui-unit"))
+                api(libs.kotlinStdlib)
+
+                implementation(project(":compose:ui:ui-util"))
+            }
+
+            jvmMain.dependencies {
+                api(project(":compose:runtime:runtime"))
+                api(libs.kotlinCoroutinesCore)
+                api(libs.kotlinCoroutinesTest)
+                api(libs.kotlinStdlibCommon)
+            }
+
+            androidMain.dependencies {
+                api(project(":compose:ui:ui-graphics"))
+
+                implementation("androidx.annotation:annotation:1.1.0")
+                implementation("androidx.core:core-ktx:1.2.0")
+                implementation("androidx.test.espresso:espresso-core:3.3.0")
+                implementation(libs.testMonitor)
+            }
+
+            androidCommonTest.dependencies {
+                implementation(project(":compose:test-utils"))
+                implementation(libs.truth)
+            }
+
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.mockitoCore4)
+                implementation(libs.mockitoKotlin4)
+            }
+
+            androidAndroidTest.dependencies {
+                implementation(project(":compose:material:material"))
+                implementation(project(":compose:ui:ui-test-junit4"))
+                implementation("androidx.activity:activity-compose:1.3.1")
+                implementation(libs.mockitoCore)
+                implementation(libs.mockitoKotlin)
+                implementation(libs.dexmakerMockito)
+                implementation(libs.kotlinTest)
+            }
+
+            desktopMain.dependencies {
+                implementation(libs.junit)
+                implementation(libs.truth)
+                implementation(libs.skiko)
+            }
+
+            androidCommonTest.dependsOn(commonTest)
+            androidTest.dependsOn(androidCommonTest)
+            androidAndroidTest.dependsOn(androidCommonTest)
+        }
+    }
+
+    dependencies {
+        // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
+        // leaks into instrumented tests (b/214407011)
+        testImplementation(libs.robolectric)
+
+        samples(project(":compose:ui:ui-test:ui-test-samples"))
+    }
 }
 
 androidx {
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.kt
index a729e09..32a03fe 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider.kt
@@ -34,6 +34,7 @@
      *
      * For usage patterns and semantics concepts see [SemanticsNodeInteraction]
      *
+     * @param matcher Matcher used for filtering
      * @param useUnmergedTree Find within merged composables like Buttons.
      * @see onAllNodes to work with multiple elements
      */
@@ -50,6 +51,7 @@
      *
      * For usage patterns and semantics concepts see [SemanticsNodeInteraction]
      *
+     * @param matcher Matcher used for filtering.
      * @param useUnmergedTree Find within merged composables like Buttons.
      * @see onNode
      */
diff --git a/compose/ui/ui-text/api/current.ignore b/compose/ui/ui-text/api/current.ignore
new file mode 100644
index 0000000..ae0c856
--- /dev/null
+++ b/compose/ui/ui-text/api/current.ignore
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+ChangedType: androidx.compose.ui.text.AnnotatedString.Builder#append(char):
+    Method androidx.compose.ui.text.AnnotatedString.Builder.append has changed return type from androidx.compose.ui.text.AnnotatedString.Builder to void
+
+
+RemovedDeprecatedMethod: androidx.compose.ui.text.AnnotatedString.Builder#deprecated_append_returning_void(char):
+    Removed deprecated method androidx.compose.ui.text.AnnotatedString.Builder.deprecated_append_returning_void(char)
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 7dcfe57..83b4fcd 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -39,7 +39,7 @@
     method public androidx.compose.ui.text.AnnotatedString.Builder append(char char);
     method public void append(androidx.compose.ui.text.AnnotatedString text);
     method public void append(androidx.compose.ui.text.AnnotatedString text, int start, int end);
-    method @Deprecated public void deprecated_append_returning_void(char char);
+    method @Deprecated public void append(char char);
     method public int getLength();
     method public void pop();
     method public void pop(int index);
@@ -484,6 +484,7 @@
   public final class TextRangeKt {
     method public static long TextRange(int start, int end);
     method public static long TextRange(int index);
+    method public static long constrain(long, int minimumValue, int maximumValue);
     method public static String substring(CharSequence, long range);
   }
 
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index 11478bf..e2807bc 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -42,7 +42,7 @@
     method public androidx.compose.ui.text.AnnotatedString.Builder append(char char);
     method public void append(androidx.compose.ui.text.AnnotatedString text);
     method public void append(androidx.compose.ui.text.AnnotatedString text, int start, int end);
-    method @Deprecated public void deprecated_append_returning_void(char char);
+    method @Deprecated public void append(char char);
     method public int getLength();
     method public void pop();
     method public void pop(int index);
@@ -522,6 +522,7 @@
   public final class TextRangeKt {
     method public static long TextRange(int start, int end);
     method public static long TextRange(int index);
+    method public static long constrain(long, int minimumValue, int maximumValue);
     method public static String substring(CharSequence, long range);
   }
 
diff --git a/compose/ui/ui-text/api/restricted_current.ignore b/compose/ui/ui-text/api/restricted_current.ignore
new file mode 100644
index 0000000..ae0c856
--- /dev/null
+++ b/compose/ui/ui-text/api/restricted_current.ignore
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+ChangedType: androidx.compose.ui.text.AnnotatedString.Builder#append(char):
+    Method androidx.compose.ui.text.AnnotatedString.Builder.append has changed return type from androidx.compose.ui.text.AnnotatedString.Builder to void
+
+
+RemovedDeprecatedMethod: androidx.compose.ui.text.AnnotatedString.Builder#deprecated_append_returning_void(char):
+    Removed deprecated method androidx.compose.ui.text.AnnotatedString.Builder.deprecated_append_returning_void(char)
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 7dcfe57..83b4fcd 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -39,7 +39,7 @@
     method public androidx.compose.ui.text.AnnotatedString.Builder append(char char);
     method public void append(androidx.compose.ui.text.AnnotatedString text);
     method public void append(androidx.compose.ui.text.AnnotatedString text, int start, int end);
-    method @Deprecated public void deprecated_append_returning_void(char char);
+    method @Deprecated public void append(char char);
     method public int getLength();
     method public void pop();
     method public void pop(int index);
@@ -484,6 +484,7 @@
   public final class TextRangeKt {
     method public static long TextRange(int start, int end);
     method public static long TextRange(int index);
+    method public static long constrain(long, int minimumValue, int maximumValue);
     method public static String substring(CharSequence, long range);
   }
 
diff --git a/compose/ui/ui-text/build.gradle b/compose/ui/ui-text/build.gradle
index 7409597..c20c781 100644
--- a/compose/ui/ui-text/build.gradle
+++ b/compose/ui/ui-text/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,15 +24,77 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+        implementation(libs.kotlinCoroutinesCore)
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api(project(":compose:ui:ui-graphics"))
+        api(project(":compose:ui:ui-unit"))
+        api("androidx.annotation:annotation:1.1.0")
+
+        // when updating the runtime version please also update the runtime-saveable version
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation("androidx.compose.runtime:runtime-saveable:1.2.1")
+
+        implementation(project(":compose:ui:ui-util"))
+        implementation(libs.kotlinStdlib)
+        implementation("androidx.core:core:1.7.0")
+        implementation('androidx.collection:collection:1.0.0')
+        implementation("androidx.emoji2:emoji2:1.2.0")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.mockitoCore4)
+        testImplementation(libs.truth)
+        testImplementation(libs.kotlinReflect)
+        testImplementation(libs.kotlinTest)
+        testImplementation(libs.mockitoKotlin4)
+
+        androidTestImplementation(project(":internal-testutils-fonts"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.mockitoKotlin)
+
+        samples(projectOrArtifact(":compose:ui:ui-text:ui-text-samples"))
+    }
+
+    android {
+        sourceSets {
+            main {
+                java.srcDirs += "${supportRootFolder}/text/text/src/main/java"
+            }
+        }
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 implementation(libs.kotlinCoroutinesCore)
 
@@ -39,62 +102,58 @@
                 api(project(":compose:ui:ui-unit"))
 
                 // when updating the runtime version please also update the runtime-saveable version
-                implementation("androidx.compose.runtime:runtime:1.2.1")
-                implementation("androidx.compose.runtime:runtime-saveable:1.2.1")
+                implementation(project(":compose:runtime:runtime"))
+                implementation(project(":compose:runtime:runtime-saveable"))
 
                 implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
+            jvmMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        if (desktopEnabled) {
             skikoMain {
                 dependsOn(commonMain)
                 dependencies {
                     api(libs.skikoCommon)
-                    implementation(project(":compose:runtime:runtime"))
-                    implementation(project(":compose:runtime:runtime-saveable"))
                 }
             }
-        }
 
-        jvmMain {
-            dependencies {
-                implementation(libs.kotlinStdlib)
+            desktopMain {
+                dependsOn(skikoMain)
+                dependsOn(jvmMain)
             }
-        }
 
+            androidMain {
+                dependsOn(commonMain)
+            }
 
-        androidMain {
-            dependsOn(commonMain)
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
                 implementation("androidx.core:core:1.7.0")
                 implementation("androidx.emoji2:emoji2:1.2.0")
                 implementation('androidx.collection:collection:1.0.0')
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
+            androidMain.kotlin.srcDirs("${supportRootFolder}/text/text/src/main/java")
+
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(project(":internal-testutils-fonts"))
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.mockitoCore4)
+                implementation(libs.truth)
+                implementation(libs.kotlinReflect)
+                implementation(libs.kotlinTest)
+                implementation(libs.mockitoKotlin4)
             }
-        }
 
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:ui:ui-test-junit4"))
                 implementation(project(":internal-testutils-fonts"))
                 implementation(libs.testRules)
@@ -106,44 +165,19 @@
                 implementation(libs.truth)
                 implementation(libs.mockitoKotlin)
             }
-        }
 
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(project(":internal-testutils-fonts"))
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.mockitoCore4)
+            desktopTest.dependencies {
                 implementation(libs.truth)
-                implementation(libs.kotlinReflect)
+                implementation(libs.junit)
                 implementation(libs.kotlinTest)
-                implementation(libs.mockitoKotlin4)
+                implementation(libs.skikoCurrentOs)
+                implementation(project(":compose:foundation:foundation"))
+                implementation(project(":compose:ui:ui-test-junit4"))
             }
         }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependencies {
-                    implementation(libs.truth)
-                    implementation(libs.junit)
-                    implementation(libs.kotlinTest)
-                    implementation(libs.skikoCurrentOs)
-                    implementation(project(":compose:foundation:foundation"))
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                    implementation(project(":internal-testutils-fonts"))
-                }
-            }
-        }
-
-        androidMain.kotlin.srcDirs("${supportRootFolder}/text/text/src/main/java")
+    }
+    dependencies {
+        samples(projectOrArtifact(":compose:ui:ui-text:ui-text-samples"))
     }
 }
 
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
index e7ffa4f..fbad0c0 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
@@ -108,7 +108,7 @@
  * @param minimumValue the minimum value that [TextRange.start] or [TextRange.end] can be.
  * @param maximumValue the exclusive maximum value that [TextRange.start] or [TextRange.end] can be.
  */
-internal fun TextRange.constrain(minimumValue: Int, maximumValue: Int): TextRange {
+fun TextRange.constrain(minimumValue: Int, maximumValue: Int): TextRange {
     val newStart = start.coerceIn(minimumValue, maximumValue)
     val newEnd = end.coerceIn(minimumValue, maximumValue)
     if (newStart != start || newEnd != end) {
diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/platform/PlatformFont.skiko.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/platform/PlatformFont.skiko.kt
index da5b016..c8a98c8 100644
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/platform/PlatformFont.skiko.kt
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/platform/PlatformFont.skiko.kt
@@ -112,6 +112,7 @@
  * Returns a Compose [Typeface] from Skia [SkTypeface].
  *
  * @param typeface Android Typeface instance
+ * @param alias a shorter name that is used as an alternative to the full font name
  */
 fun Typeface(typeface: SkTypeface, alias: String? = null): Typeface {
     return SkiaBackedTypeface(alias, typeface)
diff --git a/compose/ui/ui-tooling-data/build.gradle b/compose/ui/ui-tooling-data/build.gradle
index a7fd5b8..13f1be5 100644
--- a/compose/ui/ui-tooling-data/build.gradle
+++ b/compose/ui/ui-tooling-data/build.gradle
@@ -15,8 +15,9 @@
  */
 
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -24,15 +25,53 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+
+        implementation(libs.kotlinStdlib)
+
+        api "androidx.annotation:annotation:1.1.0"
+
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api(project(":compose:ui:ui"))
+
+        androidTestImplementation project(":compose:ui:ui-test-junit4")
+
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testRules)
+
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(project(":compose:foundation:foundation-layout"))
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation("androidx.activity:activity-compose:1.3.1")
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
+
                 implementation(libs.kotlinStdlib)
 
                 api "androidx.annotation:annotation:1.1.0"
@@ -40,58 +79,25 @@
                 api("androidx.compose.runtime:runtime:1.2.1")
                 api(project(":compose:ui:ui"))
             }
-        }
-
-        commonTest {
-            dependencies {
-                implementation(kotlin("test-junit"))
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
+            jvmMain.dependencies {
                 implementation(libs.kotlinStdlib)
             }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-
-                }
+            commonTest.dependencies {
+                implementation(kotlin("test-junit"))
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.truth)
             }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:ui:ui-test-junit4"))
 
                 implementation(libs.junit)
@@ -106,24 +112,9 @@
                 implementation("androidx.activity:activity-compose:1.3.1")
             }
         }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-
-                }
-            }
-        }
+    }
+    dependencies {
+        samples(projectOrArtifact(":compose:ui:ui-unit:ui-unit-samples"))
     }
 }
 
diff --git a/compose/ui/ui-tooling-preview/build.gradle b/compose/ui/ui-tooling-preview/build.gradle
index 7ba7e9d..a9f9236 100644
--- a/compose/ui/ui-tooling-preview/build.gradle
+++ b/compose/ui/ui-tooling-preview/build.gradle
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,94 +25,47 @@
     id("com.android.library")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        implementation(libs.kotlinStdlib)
+        api("androidx.annotation:annotation:1.2.0")
+        api("androidx.compose.runtime:runtime:1.2.1")
+        testImplementation(libs.junit)
+    }
+}
 
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
-                api("androidx.compose.runtime:runtime:1.2.1")
+                api(project(":compose:runtime:runtime"))
             }
-        }
 
-        commonTest {
-            dependencies {
-
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:runtime:runtime"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.2.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-
-                }
-            }
-        }
-
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-            }
-        }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidTest.dependencies {
                 implementation(libs.junit)
             }
         }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-
-                }
-            }
-        }
     }
 }
 
+
 androidx {
     name = "Compose Tooling API"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/compose/ui/ui-tooling/build.gradle b/compose/ui/ui-tooling/build.gradle
index 134569b..507d5fcf 100644
--- a/compose/ui/ui-tooling/build.gradle
+++ b/compose/ui/ui-tooling/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,51 +24,69 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        implementation(libs.kotlinStdlib)
+
+        api("androidx.annotation:annotation:1.1.0")
+        implementation(project(":compose:animation:animation"))
+
+        api("androidx.compose.runtime:runtime:1.2.1")
+        api(project(":compose:ui:ui"))
+        api(project(":compose:ui:ui-tooling-preview"))
+        api(project(":compose:ui:ui-tooling-data"))
+        implementation("androidx.savedstate:savedstate-ktx:1.2.1")
+        implementation("androidx.compose.material:material:1.0.0")
+        implementation("androidx.activity:activity-compose:1.7.0")
+        implementation("androidx.lifecycle:lifecycle-common:2.6.1")
+
+        // kotlin-reflect and animation-tooling-internal are provided by Studio at runtime
+        compileOnly(project(":compose:animation:animation-tooling-internal"))
+        compileOnly(libs.kotlinReflect)
+
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(project(":compose:foundation:foundation-layout"))
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.kotlinReflect)
+        androidTestImplementation(project(":compose:animation:animation-tooling-internal"))
+        androidTestImplementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
+        androidTestImplementation(project(":compose:runtime:runtime-livedata"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 api(project(":compose:ui:ui-tooling-preview"))
-                api("androidx.compose.runtime:runtime:1.2.1")
+                api(project(":compose:runtime:runtime"))
                 api(project(":compose:ui:ui"))
                 api(project(":compose:ui:ui-tooling-data"))
             }
-        }
-
-        commonTest {
-            dependencies {
-
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:runtime:runtime"))
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
                 implementation(project(":compose:animation:animation"))
                 implementation("androidx.savedstate:savedstate-ktx:1.2.1")
-                implementation("androidx.compose.material:material:1.0.0")
+                implementation(project(":compose:material:material"))
                 implementation("androidx.activity:activity-compose:1.7.0")
                 implementation("androidx.lifecycle:lifecycle-common:2.6.1")
 
@@ -75,31 +94,14 @@
                 compileOnly(project(":compose:animation:animation-tooling-internal"))
                 compileOnly(libs.kotlinReflect)
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(skikoMain)
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-                    implementation(project(":compose:runtime:runtime"))
-                    implementation(project(":compose:ui:ui"))
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
+                implementation(project(":compose:runtime:runtime"))
+                implementation(project(":compose:ui:ui"))
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(project(":compose:ui:ui-test-junit4"))
 
                 implementation(libs.junit)
@@ -115,26 +117,10 @@
                 implementation(project(":compose:runtime:runtime-livedata"))
             }
         }
-
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-
-                }
-            }
-        }
     }
 }
 
+
 androidx {
     name = "Compose Tooling"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/compose/ui/ui-unit/build.gradle b/compose/ui/ui-unit/build.gradle
index 776eb15..bfbfed7 100644
--- a/compose/ui/ui-unit/build.gradle
+++ b/compose/ui/ui-unit/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,83 +24,84 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        api(project(":compose:ui:ui-geometry"))
+        api("androidx.annotation:annotation:1.1.0")
+
+        implementation(libs.kotlinStdlib)
+        implementation("androidx.compose.runtime:runtime:1.2.1")
+        implementation(project(":compose:ui:ui-util"))
+
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testExtJunit)
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.kotlinTest)
+
+        samples(projectOrArtifact(":compose:ui:ui-unit:ui-unit-samples"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 api(project(":compose:ui:ui-geometry"))
 
-                implementation("androidx.compose.runtime:runtime:1.2.1")
+                implementation(project(":compose:runtime:runtime"))
                 implementation(project(":compose:ui:ui-util"))
             }
-        }
-
-        commonTest {
-            dependencies {
-                implementation(kotlin("test-junit"))
-            }
-        }
-
-        jvmMain {
-            dependencies {
+            jvmMain.dependencies {
                 implementation(libs.kotlinStdlib)
             }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(project(":compose:runtime:runtime"))
-                }
+            commonTest.dependencies {
+                implementation(kotlin("test-junit"))
             }
-        }
 
-        jvmTest {
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.truth)
             }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            androidAndroidTest.dependencies {
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
                 implementation(libs.testExtJunit)
                 implementation(libs.espressoCore)
             }
         }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.truth)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
+    }
+    dependencies {
+        samples(projectOrArtifact(":compose:ui:ui-unit:ui-unit-samples"))
     }
 }
 
diff --git a/compose/ui/ui-util/build.gradle b/compose/ui/ui-util/build.gradle
index 4c19723..8eeb75e 100644
--- a/compose/ui/ui-util/build.gradle
+++ b/compose/ui/ui-util/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -23,72 +24,59 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    dependencies {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        implementation(libs.kotlinStdlib)
+
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.kotlinTest)
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
             }
-        }
 
-        commonTest {
-            dependencies {
+            jvmMain.dependencies {
+                implementation(libs.kotlinStdlib)
+            }
+
+            androidMain.dependencies {
+                implementation(libs.kotlinStdlib)
+            }
+
+            commonTest.dependencies {
                 implementation(kotlin("test-junit"))
             }
-        }
 
-        jvmMain {
-            dependencies {
-                implementation(libs.kotlinStdlib)
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
-                implementation(libs.kotlinStdlib)
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-            }
-        }
-
-        jvmTest {
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
-            }
-        }
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
                 implementation(libs.truth)
             }
         }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-            }
-        }
     }
 }
 
diff --git a/compose/ui/ui-viewbinding/build.gradle b/compose/ui/ui-viewbinding/build.gradle
index 7b4d99d..901810d 100644
--- a/compose/ui/ui-viewbinding/build.gradle
+++ b/compose/ui/ui-viewbinding/build.gradle
@@ -39,6 +39,8 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
+
+    samples(project(":compose:ui:ui-viewbinding:ui-viewbinding-samples"))
 }
 
 androidx {
diff --git a/compose/ui/ui/api/current.ignore b/compose/ui/ui/api/current.ignore
index 750e9a7..2001639 100644
--- a/compose/ui/ui/api/current.ignore
+++ b/compose/ui/ui/api/current.ignore
@@ -1,7 +1,3 @@
 // Baseline format: 1.0
 RemovedClass: androidx.compose.ui.platform.AndroidComposeView_androidKt:
     Removed class androidx.compose.ui.platform.AndroidComposeView_androidKt
-
-// see b/275084979 for details. API not actually removed, but metalave confused by JvmName + Deprecated
-RemovedMethod: androidx.compose.ui.ComposedModifierKt#materialize(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier):
-    Removed method androidx.compose.ui.ComposedModifierKt.materialize(androidx.compose.runtime.Composer,androidx.compose.ui.Modifier)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 09ca478..4eb047f 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -113,8 +113,8 @@
 
   public final class ComposedModifierKt {
     method public static androidx.compose.ui.Modifier composed(androidx.compose.ui.Modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.InspectorInfo,kotlin.Unit> inspectorInfo, kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier,? extends androidx.compose.ui.Modifier> factory);
+    method @Deprecated public static androidx.compose.ui.Modifier materialize(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
     method public static androidx.compose.ui.Modifier materializeModifier(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
-    method @Deprecated public static androidx.compose.ui.Modifier materializeWithCompositionLocalInjection(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
   }
 
   @androidx.compose.runtime.Stable @kotlin.jvm.JvmDefaultWithCompatibility public interface Modifier {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index eb255a5..7e1d053 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -117,8 +117,8 @@
     method @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier composed(androidx.compose.ui.Modifier, String fullyQualifiedName, Object? key1, Object? key2, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.InspectorInfo,kotlin.Unit> inspectorInfo, kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier,? extends androidx.compose.ui.Modifier> factory);
     method @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier composed(androidx.compose.ui.Modifier, String fullyQualifiedName, Object? key1, Object? key2, Object? key3, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.InspectorInfo,kotlin.Unit> inspectorInfo, kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier,? extends androidx.compose.ui.Modifier> factory);
     method @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier composed(androidx.compose.ui.Modifier, String fullyQualifiedName, Object![]? keys, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.InspectorInfo,kotlin.Unit> inspectorInfo, kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier,? extends androidx.compose.ui.Modifier> factory);
+    method @Deprecated public static androidx.compose.ui.Modifier materialize(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
     method public static androidx.compose.ui.Modifier materializeModifier(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
-    method @Deprecated public static androidx.compose.ui.Modifier materializeWithCompositionLocalInjection(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
   }
 
   @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalComposeUiApi {
diff --git a/compose/ui/ui/api/restricted_current.ignore b/compose/ui/ui/api/restricted_current.ignore
index ef0ff9c..2001639 100644
--- a/compose/ui/ui/api/restricted_current.ignore
+++ b/compose/ui/ui/api/restricted_current.ignore
@@ -1,7 +1,3 @@
 // Baseline format: 1.0
 RemovedClass: androidx.compose.ui.platform.AndroidComposeView_androidKt:
     Removed class androidx.compose.ui.platform.AndroidComposeView_androidKt
-
-
-RemovedMethod: androidx.compose.ui.ComposedModifierKt#materialize(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier):
-    Removed method androidx.compose.ui.ComposedModifierKt.materialize(androidx.compose.runtime.Composer,androidx.compose.ui.Modifier)
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 5be72cd..8b45d71 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -113,8 +113,8 @@
 
   public final class ComposedModifierKt {
     method public static androidx.compose.ui.Modifier composed(androidx.compose.ui.Modifier, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.InspectorInfo,kotlin.Unit> inspectorInfo, kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier,? extends androidx.compose.ui.Modifier> factory);
+    method @Deprecated public static androidx.compose.ui.Modifier materialize(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
     method public static androidx.compose.ui.Modifier materializeModifier(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
-    method @Deprecated public static androidx.compose.ui.Modifier materializeWithCompositionLocalInjection(androidx.compose.runtime.Composer, androidx.compose.ui.Modifier modifier);
   }
 
   @androidx.compose.runtime.Stable @kotlin.jvm.JvmDefaultWithCompatibility public interface Modifier {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 76d4419b..2b2f069 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import androidx.build.KmpPlatformsKt
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 import static androidx.inspection.gradle.InspectionPluginKt.packageInspector
 
@@ -25,16 +26,130 @@
     id("AndroidXComposePlugin")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
+    constraints {
+        // In 1.4.0-alpha02 there was a change made in :compose:ui:ui which fixed an issue where
+        // we were over-invalidating layout. This change caused a corresponding regression in
+        // foundation's CoreText, where it was expecting a layout to happen but with this change
+        // it would not. A corresponding fix for this was added in 1.4.0-alpha02 of
+        // :compose:foundation:foundation. By adding this constraint, we are ensuring that the
+        // if an app has this ui module _and_ the foundation module as a dependency, then the
+        // version of foundation will be at least this version. This will prevent the bug in
+        // foundation from occurring. This does _NOT_ require that the app have foundation as
+        // a dependency.
+        implementation(project(":compose:foundation:foundation")) {
+            because 'prevents a critical bug in Text'
+        }
+    }
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+        implementation(libs.kotlinCoroutinesCore)
 
-    sourceSets {
-        commonMain {
-            dependencies {
+        // when updating the runtime version please also update the runtime-saveable version
+        implementation(project(":compose:runtime:runtime"))
+        api(project(":compose:runtime:runtime-saveable"))
+
+        api(project(":compose:ui:ui-geometry"))
+        api(project(":compose:ui:ui-graphics"))
+        api(project(":compose:ui:ui-text"))
+        api(project(":compose:ui:ui-unit"))
+        api("androidx.annotation:annotation:1.5.0")
+
+        // This has stub APIs for access to legacy Android APIs, so we don't want
+        // any dependency on this module.
+        compileOnly(project(":compose:ui:ui-android-stubs"))
+
+        implementation(project(":compose:ui:ui-util"))
+        implementation(libs.kotlinStdlib)
+        implementation("androidx.autofill:autofill:1.0.0")
+        implementation(libs.kotlinCoroutinesAndroid)
+
+        // Used to generate debug information in the layout inspector. If not present,
+        // we may fall back to more limited data.
+        compileOnly(libs.kotlinReflect)
+        testImplementation(libs.kotlinReflect)
+
+        implementation("androidx.activity:activity-ktx:1.7.0")
+        implementation(project(":core:core"))
+        implementation('androidx.collection:collection:1.0.0')
+        implementation("androidx.customview:customview-poolingcontainer:1.0.0")
+        implementation("androidx.savedstate:savedstate-ktx:1.2.1")
+        implementation("androidx.lifecycle:lifecycle-runtime:2.6.1")
+        implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1")
+        implementation("androidx.profileinstaller:profileinstaller:1.3.0")
+        implementation("androidx.emoji2:emoji2:1.2.0")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.kotlinCoroutinesTest)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+        testImplementation(libs.mockitoCore4)
+        testImplementation(libs.mockitoKotlin4)
+        testImplementation(libs.robolectric)
+        testImplementation(project(":compose:ui:ui-test-junit4"))
+        testImplementation(project(":compose:test-utils"))
+
+        androidTestImplementation(libs.testCore)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.testExtJunitKtx)
+        androidTestImplementation(libs.testUiautomator)
+        androidTestImplementation(libs.kotlinCoroutinesTest)
+        androidTestImplementation(libs.kotlinTest)
+        androidTestImplementation(libs.espressoCore)
+        androidTestImplementation(libs.bundles.espressoContrib)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.dexmakerMockito)
+        androidTestImplementation(libs.mockitoCore)
+        androidTestImplementation(libs.truth)
+        androidTestImplementation(libs.mockitoKotlin)
+        androidTestImplementation(libs.material)
+        androidTestImplementation(project(":compose:animation:animation-core"))
+        androidTestImplementation(project(":compose:foundation:foundation"))
+        androidTestImplementation(project(":compose:foundation:foundation-layout"))
+        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation(project(":compose:test-utils"))
+        androidTestImplementation(project(":internal-testutils-fonts"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(project(":internal-testutils-runtime"))
+        androidTestImplementation(project(":test:screenshot:screenshot"))
+        androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing:2.6.1")
+        androidTestImplementation("androidx.recyclerview:recyclerview:1.3.0-alpha02")
+        androidTestImplementation("androidx.core:core-ktx:1.9.0")
+        androidTestImplementation("androidx.activity:activity-compose:1.7.0")
+        androidTestImplementation("androidx.appcompat:appcompat:1.3.0")
+        androidTestImplementation("androidx.fragment:fragment:1.3.0")
+
+        lintChecks(project(":compose:ui:ui-lint"))
+        lintPublish(project(":compose:ui:ui-lint"))
+
+        samples(project(":compose:ui:ui:ui-samples"))
+    }
+}
+
+packageInspector(project, ":compose:ui:ui-inspection")
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
                 implementation(libs.kotlinCoroutinesCore)
 
@@ -48,33 +163,8 @@
                 api project(":compose:ui:ui-unit")
                 implementation(project(":compose:ui:ui-util"))
             }
-        }
 
-        commonTest {
-            dependencies {
-                implementation(libs.kotlinReflect)
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-            }
-        }
-
-        if (desktopEnabled) {
-            skikoMain {
-                dependsOn(commonMain)
-                dependencies {
-                    api(project(":compose:ui:ui-graphics"))
-                    api(libs.skikoCommon)
-                }
-            }
-        }
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 implementation(libs.kotlinStdlib)
                 // This has stub APIs for access to legacy Android APIs, so we don't want
                 // any dependency on this module.
@@ -91,34 +181,48 @@
                 implementation("androidx.lifecycle:lifecycle-runtime:2.6.1")
                 implementation("androidx.lifecycle:lifecycle-viewmodel:2.6.1")
                 implementation("androidx.emoji2:emoji2:1.2.0")
-
-                implementation("androidx.profileinstaller:profileinstaller:1.3.0")
             }
-        }
 
-        if (desktopEnabled) {
+            jvmMain.dependencies {
+                implementation(libs.kotlinStdlib)
+            }
+            skikoMain {
+                dependsOn(commonMain)
+                dependencies {
+                    api(project(":compose:ui:ui-graphics"))
+                    api(libs.skikoCommon)
+                }
+            }
             desktopMain {
                 dependsOn(skikoMain)
-                dependsOn(jvmMain)
                 dependencies {
-                    implementation(libs.kotlinStdlib)
                     implementation(libs.kotlinStdlibJdk8)
                     api(libs.kotlinCoroutinesSwing)
                 }
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
+            commonTest.dependencies {
+                implementation(libs.kotlinReflect)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.kotlinCoroutinesTest)
+                implementation(libs.junit)
+                implementation(libs.truth)
+                implementation(libs.mockitoCore4)
+                implementation(libs.mockitoKotlin4)
+                implementation(project(":compose:ui:ui-test-junit4"))
+                implementation(project(":internal-testutils-fonts"))
+                implementation(project(":compose:test-utils"))
+            }
+
+            androidAndroidTest.dependencies {
                 implementation("androidx.fragment:fragment:1.3.0")
                 implementation("androidx.appcompat:appcompat:1.3.0")
                 implementation(libs.testUiautomator)
@@ -149,76 +253,27 @@
                 implementation("androidx.core:core-ktx:1.2.0")
                 implementation("androidx.activity:activity-compose:1.7.0")
             }
-        }
 
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.kotlinCoroutinesTest)
-                implementation(libs.junit)
+            desktopTest.dependencies {
                 implementation(libs.truth)
-                implementation(libs.mockitoCore4)
-                implementation(libs.mockitoKotlin4)
+                implementation(libs.junit)
+                implementation(libs.mockitoCore)
+                implementation(libs.mockitoKotlin)
+                implementation(libs.skikoCurrentOs)
+                implementation(project(":compose:material:material"))
                 implementation(project(":compose:ui:ui-test-junit4"))
-                implementation(project(":internal-testutils-fonts"))
-                implementation(project(":compose:test-utils"))
-            }
-        }
-
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                    implementation(libs.truth)
-                    implementation(libs.junit)
-                    implementation(libs.mockitoCore)
-                    implementation(libs.mockitoKotlin)
-                    implementation(libs.skikoCurrentOs)
-                    implementation(project(":compose:material:material"))
-                    implementation(project(":compose:ui:ui-test-junit4"))
-                }
             }
         }
     }
-}
+    dependencies {
+        samples(project(":compose:ui:ui:ui-samples"))
 
-dependencies {
-
-    constraints {
-        // In 1.4.0-alpha02 there was a change made in :compose:ui:ui which fixed an issue where
-        // we were over-invalidating layout. This change caused a corresponding regression in
-        // foundation's CoreText, where it was expecting a layout to happen but with this change
-        // it would not. A corresponding fix for this was added in 1.4.0-alpha02 of
-        // :compose:foundation:foundation. By adding this constraint, we are ensuring that the
-        // if an app has this ui module _and_ the foundation module as a dependency, then the
-        // version of foundation will be at least this version. This will prevent the bug in
-        // foundation from occurring. This does _NOT_ require that the app have foundation as
-        // a dependency.
-        implementation(project(":compose:foundation:foundation")) {
-            because 'prevents a critical bug in Text'
-        }
+        // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
+        // leaks into instrumented tests (b/214407011)
+        testImplementation(libs.robolectric)
     }
 }
 
-packageInspector(project, ":compose:ui:ui-inspection")
-
-dependencies {
-    lintChecks(project(":compose:ui:ui-lint"))
-    lintPublish(project(":compose:ui:ui-lint"))
-
-    // Can't declare this in kotlin { sourceSets { androidTest.dependencies { .. } } } as that
-    // leaks into instrumented tests (b/214407011)
-    testImplementation(libs.robolectric)
-}
-
 androidx {
     name = "Compose UI primitives"
     type = LibraryType.PUBLISHED_LIBRARY
@@ -227,7 +282,7 @@
     legacyDisableKotlinStrictApiMode = true
 }
 
-if (desktopEnabled) {
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
     tasks.findByName("desktopTest").configure {
         systemProperties["GOLDEN_PATH"] = project.rootDir.absolutePath + "/../../golden"
     }
@@ -250,4 +305,23 @@
     testNamespace "androidx.compose.ui.tests"
 }
 
-
+// Diagnostics for b/188565660
+def verifyKotlinModule(String variant) {
+    project.afterEvaluate {
+        def capitalVariant = variant.capitalize()
+        def moduleFile = new File("${buildDir}/tmp/kotlin-classes/${variant}/META-INF/ui_${variant}.kotlin_module")
+        tasks.named("compile${capitalVariant}Kotlin").configure { t ->
+            t.doLast {
+                // This file should be large, about 3.2K. If this file is short then many symbols will fail to resolve
+                if (moduleFile.length() < 250) {
+                    throw new GradleException("kotlin_module file ($moduleFile) too short! See b/188565660 for more information. File text: ${moduleFile.text}")
+                }
+            }
+        }
+    }
+}
+if (!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    for (variant in ["debug", "release"]) {
+        verifyKotlinModule(variant)
+    }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
index 74a02fcf..6ceb34f 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearchPreviousTest.kt
@@ -275,6 +275,72 @@
     }
 
     @Test
+    fun focusMovesToParent() {
+        // Arrange.
+        val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) }
+        rule.setContentForTest {
+            FocusableBox(parent, 0, 0, 10, 10) {
+                FocusableBox(child1, 10, 0, 10, 10, initialFocus)
+                FocusableBox(child2, 20, 0, 10, 10)
+                FocusableBox(child3, 20, 0, 10, 10)
+            }
+        }
+
+        // Act.
+        val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) }
+
+        // Assert.
+        rule.runOnIdle {
+            assertThat(movedFocusSuccessfully).isTrue()
+            assertThat(parent.value).isTrue()
+        }
+    }
+
+    @Test
+    fun focusMovesToParent_ignoresDeactivated() {
+        // Arrange.
+        val (item, parent, child1, child2) = List(4) { mutableStateOf(false) }
+        rule.setContentForTest {
+            FocusableBox(item, 0, 0, 10, 10)
+            FocusableBox(parent, 0, 0, 10, 10, deactivated = true) {
+                FocusableBox(child1, 10, 0, 10, 10, initialFocus)
+                FocusableBox(child2, 20, 0, 10, 10)
+            }
+        }
+
+        // Act.
+        val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) }
+
+        // Assert.
+        rule.runOnIdle {
+            assertThat(movedFocusSuccessfully).isTrue()
+            assertThat(item.value).isTrue()
+        }
+    }
+
+    @Test
+    fun focusMovesToParent_ignoresDeactivated_andWrapsAround() {
+        // Arrange.
+        val (parent, child1, child2, child3) = List(4) { mutableStateOf(false) }
+        rule.setContentForTest {
+            FocusableBox(parent, 0, 0, 10, 10, deactivated = true) {
+                FocusableBox(child1, 10, 0, 10, 10, initialFocus)
+                FocusableBox(child2, 20, 0, 10, 10)
+                FocusableBox(child3, 0, 0, 10, 10)
+            }
+        }
+
+        // Act.
+        val movedFocusSuccessfully = rule.runOnIdle { focusManager.moveFocus(Previous) }
+
+        // Assert.
+        rule.runOnIdle {
+            assertThat(movedFocusSuccessfully).isTrue()
+            assertThat(child3.value).isTrue()
+        }
+    }
+
+    @Test
     fun focusWrapsAroundToLastItem() {
         // Arrange.
         val (item1, item2, item3) = List(3) { mutableStateOf(false) }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt
index 38834d1..c166a2e 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusEnterTest.kt
@@ -36,9 +36,9 @@
     @get:Rule
     val rule = createComposeRule()
 
-    val focusRequester = FocusRequester()
-    var enterTriggered = false
-    lateinit var focusState: FocusState
+    private val focusRequester = FocusRequester()
+    private var enterTriggered = false
+    private lateinit var focusState: FocusState
 
     @Test
     fun gainingFocus_doesNotTriggersEnter() {
@@ -423,4 +423,60 @@
             assertThat(destinationFocusState.isFocused).isTrue()
         }
     }
-}
\ No newline at end of file
+
+    @Test
+    fun redirectingFocusRequestOnChild1ToChild2_focusEnterIsCalled() {
+        // Arrange.
+        val (initialFocus, child1, child2) = FocusRequester.createRefs()
+        var enterCount = 0
+        rule.setFocusableContent {
+            Box(Modifier.focusTarget()) {
+                Box(
+                    Modifier
+                        .focusRequester(initialFocus)
+                        .focusTarget()
+                )
+                Box(
+                    Modifier
+                        .focusProperties {
+                            enter = {
+                                enterCount++
+                                child2
+                            }
+                        }
+                        .focusTarget()
+                ) {
+                    Box(
+                        Modifier
+                            .focusRequester(child1)
+                            .focusTarget()
+                    )
+                    Box(
+                        Modifier
+                            .focusRequester(child2)
+                            .focusTarget()
+                    )
+                }
+            }
+        }
+        rule.runOnIdle { initialFocus.requestFocus() }
+
+        // Act.
+        rule.runOnIdle { child1.requestFocus() }
+
+        // Assert.
+        rule.runOnIdle { assertThat(enterCount).isEqualTo(1) }
+
+        // Reset - To ensure that focus enter is called every time we enter.
+        rule.runOnIdle {
+            initialFocus.requestFocus()
+            enterCount = 0
+        }
+
+        // Act.
+        rule.runOnIdle { child1.requestFocus() }
+
+        // Assert.
+        rule.runOnIdle { assertThat(enterCount).isEqualTo(1) }
+    }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt
new file mode 100644
index 0000000..834b2a0
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/RequestFocusExitTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.focus
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalComposeUiApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class RequestFocusExitTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun redirectingFocusExitFromChild1ToChild2_focusExitIsCalled() {
+        // Arrange.
+        val (destination, child1, child2) = FocusRequester.createRefs()
+        var exitCount = 0
+        rule.setFocusableContent {
+            Box(Modifier.focusTarget()) {
+                Box(
+                    Modifier
+                        .focusRequester(destination)
+                        .focusTarget()
+                )
+                Box(
+                    Modifier
+                        .focusProperties {
+                            exit = {
+                                exitCount++
+                                child2
+                            }
+                        }
+                        .focusTarget()
+                ) {
+                    Box(
+                        Modifier
+                            .focusRequester(child1)
+                            .focusTarget()
+                    )
+                    Box(
+                        Modifier
+                            .focusRequester(child2)
+                            .focusTarget()
+                    )
+                }
+            }
+        }
+        rule.runOnIdle { child1.requestFocus() }
+
+        // Act.
+        rule.runOnIdle { destination.requestFocus() }
+
+        // Assert.
+        rule.runOnIdle { assertThat(exitCount).isEqualTo(1) }
+
+        // Reset - To ensure that focus exit is called every time we exit.
+        rule.runOnIdle {
+            child1.requestFocus()
+            exitCount = 0
+        }
+
+        // Act.
+        rule.runOnIdle { destination.requestFocus() }
+
+        // Assert.
+        rule.runOnIdle { assertThat(exitCount).isEqualTo(1) }
+    }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropFilterTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropFilterTest.kt
index f761c28..32fd60c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropFilterTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInteropFilterTest.kt
@@ -4405,3 +4405,38 @@
 )
 
 internal typealias PointerEventHandler = (PointerEvent, PointerEventPass, IntSize) -> Unit
+
+private fun PointerEventHandler.invokeOverAllPasses(
+    pointerEvent: PointerEvent,
+    size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
+) {
+    invokeOverPasses(
+        pointerEvent,
+        listOf(
+            PointerEventPass.Initial,
+            PointerEventPass.Main,
+            PointerEventPass.Final
+        ),
+        size = size
+    )
+}
+
+private fun PointerEventHandler.invokeOverPasses(
+    pointerEvent: PointerEvent,
+    vararg pointerEventPasses: PointerEventPass,
+    size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
+) {
+    invokeOverPasses(pointerEvent, pointerEventPasses.toList(), size)
+}
+
+private fun PointerEventHandler.invokeOverPasses(
+    pointerEvent: PointerEvent,
+    pointerEventPasses: List<PointerEventPass>,
+    size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
+) {
+    require(pointerEvent.changes.isNotEmpty())
+    require(pointerEventPasses.isNotEmpty())
+    pointerEventPasses.forEach {
+        this.invoke(pointerEvent, it, size)
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
index ce3d08b7..af27c0d 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/TestUtils.kt
@@ -36,6 +36,7 @@
 import com.google.common.truth.Subject.Factory
 import com.google.common.truth.Truth
 
+@OptIn(ExperimentalComposeUiApi::class)
 internal fun PointerInputEventData(
     id: Int,
     uptime: Long,
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadLayoutTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadLayoutTest.kt
index c9a9cd1..6f9dba1 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadLayoutTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadLayoutTest.kt
@@ -39,6 +39,7 @@
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.requiredWidth
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.sizeIn
@@ -523,6 +524,60 @@
     }
 
     @Test
+    fun defaultMeasurePolicyInSubcomposeLayout() {
+        var actualLookaheadSize by mutableStateOf(IntSize.Zero)
+        var defaultIntermediateMeasureSize by mutableStateOf(IntSize.Zero)
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                LookaheadScope {
+                    SubcomposeLayout(
+                        Modifier
+                            .fillMaxSize()
+                            .requiredSize(200.dp),
+                        intermediateMeasurePolicy = { constraints ->
+                            measurablesForSlot(Unit)[0].measure(constraints)
+                            actualLookaheadSize = this.lookaheadSize
+                            layout(0, 0) {}
+                        }
+                    ) { constraints ->
+                        val placeable = subcompose(Unit) {
+                            Box(Modifier.requiredSize(400.dp, 600.dp))
+                        }[0].measure(constraints)
+                        layout(500, 300) {
+                            placeable.place(0, 0)
+                        }
+                    }
+                    SubcomposeLayout(
+                        Modifier
+                            .size(150.dp)
+                            .intermediateLayout { measurable, _ ->
+                                measurable
+                                    .measure(Constraints(0, 2000, 0, 2000))
+                                    .run {
+                                        defaultIntermediateMeasureSize = IntSize(width, height)
+                                        layout(width, height) {
+                                            place(0, 0)
+                                        }
+                                    }
+                            }
+                    ) { constraints ->
+                        val placeable = subcompose(Unit) {
+                            Box(Modifier.requiredSize(400.dp, 600.dp))
+                        }[0].measure(constraints)
+                        layout(500, 300) {
+                            placeable.place(0, 0)
+                        }
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertEquals(IntSize(500, 300), actualLookaheadSize)
+            assertEquals(IntSize(500, 300), defaultIntermediateMeasureSize)
+        }
+    }
+
+    @Test
     fun lookaheadStaysTheSameDuringAnimationTest() {
         var isLarge by mutableStateOf(true)
         var parentLookaheadSize = IntSize.Zero
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
index 6ae25e4..6409344 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/modifier/ModifierNodeReuseAndDeactivationTest.kt
@@ -18,7 +18,9 @@
 
 package androidx.compose.ui.modifier
 
+import androidx.compose.runtime.Applier
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReusableComposeNode
 import androidx.compose.runtime.ReusableContent
 import androidx.compose.runtime.ReusableContentHost
 import androidx.compose.runtime.getValue
@@ -35,9 +37,11 @@
 import androidx.compose.ui.layout.MeasurePolicy
 import androidx.compose.ui.layout.MeasureResult
 import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.node.ComposeUiNode
 import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.DrawModifierNode
 import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.node.ObserverNode
 import androidx.compose.ui.node.observeReads
@@ -49,6 +53,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -233,6 +238,54 @@
         }
     }
 
+    // Regression test for b/275919849
+    @Test
+    fun unchangedNodesAreDetachedAndReattachedWhenReused() {
+        val nodeInstance = object : Modifier.Node() {}
+        val element = object : ModifierNodeElement<Modifier.Node>() {
+            override fun create(): Modifier.Node = nodeInstance
+            override fun hashCode(): Int = System.identityHashCode(this)
+            override fun equals(other: Any?) = (other === this)
+            override fun update(node: Modifier.Node) = nodeInstance
+        }
+
+        var active by mutableStateOf(true)
+        rule.setContent {
+            ReusableContentHost(active) {
+                // Custom Layout that measures to 1x1 pixels and only assigns the modifiers once
+                // when the node is created. Even if the modifiers aren't reassigned, they should
+                // still undergo the same lifecycle.
+                ReusableComposeNode<ComposeUiNode, Applier<Any>>(
+                    factory = {
+                        LayoutNode().apply {
+                            measurePolicy = MeasurePolicy { _, _ -> layout(1, 1) {} }
+                            modifier = element
+                        }
+                    },
+                    update = { },
+                    content = { }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            assertWithMessage("Modifier Node was not attached when being initially created")
+                .that(nodeInstance.isAttached).isTrue()
+        }
+
+        active = false
+        rule.runOnIdle {
+            assertWithMessage("Modifier Node should be detached when its LayoutNode is deactivated")
+                .that(nodeInstance.isAttached).isFalse()
+        }
+
+        active = true
+        rule.runOnIdle {
+            assertWithMessage("Modifier Node was not attached after being reactivated")
+                .that(nodeInstance.isAttached).isTrue()
+        }
+    }
+
     @Test
     fun nodesAreDetachedAndAttachedWhenDeactivatedAndReactivated() {
         var active by mutableStateOf(true)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainOwnerTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainOwnerTests.kt
new file mode 100644
index 0000000..da15bc0
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainOwnerTests.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalComposeUiApi::class)
+package androidx.compose.ui.node
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.dp
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+
+class NodeChainOwnerTests {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun getModifierNode_returnsLayers_whenGraphicsLayerIsTail() {
+        rule.setContent {
+            // box gets the root graphics layer applied to it
+            Box {
+                // test this, with no graphicsLayers added externally
+                Layout(
+                    modifier = Modifier.testTag("tag").graphicsLayer(),
+                    EmptyMeasurePolicy())
+            }
+        }
+
+        val modifierInfo = rule.onNodeWithTag("tag")
+            .fetchSemanticsNode()
+            .layoutInfo
+            .getModifierInfo()
+        assertThat(modifierInfo.mapNotNull { it.extra }).hasSize(1)
+    }
+
+    @Test
+    fun getModifierNode_returnsLayersWhenHead_noOtherLayout() {
+        rule.setContent {
+            // box gets the root graphics layer applied to it
+            Box {
+                // test this, with no graphicsLayers added externally
+                Layout(
+                    modifier = Modifier.graphicsLayer().semantics {}.testTag("tag"),
+                    EmptyMeasurePolicy())
+            }
+        }
+
+        val modifierInfo = rule.onNodeWithTag("tag")
+            .fetchSemanticsNode()
+            .layoutInfo
+            .getModifierInfo()
+        assertThat(modifierInfo.mapNotNull { it.extra }).hasSize(2)
+    }
+
+    @Test
+    fun getModifierNode_returnsLayersWhenHead_whenTailLayoutLayout() {
+        rule.setContent {
+            // box gets the root graphics layer applied to it
+            Box {
+                // test this, with no graphicsLayers added externally
+                Layout(
+                    modifier = Modifier.graphicsLayer().size(30.dp).testTag("tag"),
+                    EmptyMeasurePolicy())
+            }
+        }
+
+        val modifierInfo = rule.onNodeWithTag("tag")
+            .fetchSemanticsNode()
+            .layoutInfo
+            .getModifierInfo()
+        assertThat(modifierInfo.mapNotNull { it.extra }).hasSize(1)
+    }
+}
+
+class EmptyMeasurePolicy : MeasurePolicy {
+    override fun MeasureScope.measure(
+        measurables: List<Measurable>,
+        constraints: Constraints
+    ): MeasureResult {
+        return layout(constraints.maxWidth, constraints.maxHeight, placementBlock = {})
+    }
+}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
index f13a71f..523ffc7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/node/NodeChainTests.kt
@@ -20,6 +20,7 @@
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.areObjectsOfSameType
+import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
 class NodeChainTests {
@@ -141,6 +142,18 @@
             }
     }
 
+    @Test
+    fun getModifierNode_returnsModifiers() {
+        val a = modifierA()
+        val b = modifierB()
+        val modifierInfo = chainTester()
+            .withModifiers(a, b)
+            .chain
+            .getModifierInfo()
+
+        assertThat(modifierInfo.map { it.modifier }).isEqualTo(listOf(a, b))
+    }
+
     // TODO(b/241856927)
     // - aggregate masks are correct
     // - tree traversal
@@ -150,4 +163,4 @@
     // - number of inserts/deletes/etc for different types of updates
     // - ensure which same-size updates go through diff vs not
     // - ensure that entities in chain are attached, out of chain are detached
-}
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt
index dac3281..5b5c194 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTargetModifierNode.kt
@@ -112,10 +112,13 @@
     ) {
         if (!isProcessingCustomEnter) {
             isProcessingCustomEnter = true
-            fetchFocusProperties().enter(focusDirection).also {
-                if (it !== Default) block(it)
+            try {
+                fetchFocusProperties().enter(focusDirection).also {
+                    if (it !== Default) block(it)
+                }
+            } finally {
+                isProcessingCustomEnter = false
             }
-            isProcessingCustomEnter = false
         }
     }
 
@@ -136,10 +139,13 @@
     ) {
         if (!isProcessingCustomExit) {
             isProcessingCustomExit = true
-            fetchFocusProperties().exit(focusDirection).also {
-                if (it !== Default) block(it)
+            try {
+                fetchFocusProperties().exit(focusDirection).also {
+                    if (it !== Default) block(it)
+                }
+            } finally {
+                isProcessingCustomExit = false
             }
-            isProcessingCustomExit = false
         }
     }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
index 2c91c1c..a60201a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
@@ -68,10 +68,9 @@
 
         // Unlike forwardFocusSearch, backwardFocusSearch visits the children before the parent.
         when (focusedChild.focusStateImpl) {
-            ActiveParent ->
-                focusedChild.backwardFocusSearch(onFound) ||
+            ActiveParent -> focusedChild.backwardFocusSearch(onFound) ||
                 generateAndSearchChildren(focusedChild, Previous, onFound) ||
-                (fetchFocusProperties().canFocus && onFound.invoke(focusedChild))
+                (focusedChild.fetchFocusProperties().canFocus && onFound.invoke(focusedChild))
 
             // Since this item "is focused", it means we already visited all its children.
             // So just search among its siblings.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutInfo.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutInfo.kt
index cb2fd62..b269a9d 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutInfo.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LayoutInfo.kt
@@ -91,4 +91,8 @@
     val modifier: Modifier,
     val coordinates: LayoutCoordinates,
     val extra: Any? = null
-)
+) {
+    override fun toString(): String {
+        return "ModifierInfo($modifier, $coordinates, $extra)"
+    }
+}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
index b090a74..c42301b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
@@ -559,6 +559,7 @@
     private val slotIdToNode = mutableMapOf<Any?, LayoutNode>()
     private val scope = Scope()
     private val intermediateMeasureScope = IntermediateMeasureScopeImpl()
+    private var lookaheadMeasuredSize: IntSize = IntSize.Zero
 
     /**
      * Default intermediate measure policy. It measures the children with the lookahead constraints
@@ -848,6 +849,7 @@
                 currentIndex = 0
                 val result = scope.block(constraints)
                 val indexAfterMeasure = currentIndex
+                lookaheadMeasuredSize = IntSize(result.width, result.height)
                 return object : MeasureResult {
                     override val width: Int
                         get() = result.width
@@ -997,8 +999,12 @@
         override fun measurablesForSlot(slotId: Any?): List<Measurable> =
             slotIdToNode[slotId]?.childMeasurables ?: emptyList()
 
+        /**
+         * This is the size returned in the MeasureResult in the measure policy from the lookahead
+         * pass.
+         */
         override val lookaheadSize: IntSize
-            get() = root.layoutDelegate.lookaheadPassDelegate!!.run { IntSize(width, height) }
+            get() = lookaheadMeasuredSize
     }
 }
 
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 39c3291..e3002c8 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
@@ -1342,6 +1342,8 @@
         } else {
             resetModifierState()
         }
+        // resetModifierState detaches all nodes, so we need to re-attach them upon reuse.
+        nodes.attach()
     }
 
     override fun onDeactivate() {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index 5684882..d99ba77 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -294,7 +294,31 @@
         var i = 0
         headToTailExclusive { node ->
             val coordinator = requireNotNull(node.coordinator)
-            infoList += ModifierInfo(current[i++], coordinator, coordinator.layer)
+            // placeWithLayer puts the layer on the _next_ coordinator
+            //
+            // - If the last node does placeWithLayer, the layer is on the innerCoordinator
+            // - the first LayoutNode in the tree gets a layer from the root
+            //
+            // This logic prefers to use this.layer, but will use innerCoordinator on the last node
+            // -- this exists for ui-inspector and must remain stable due to a non-same-version
+            // release dependency on tree structure.
+            val currentNodeLayer = coordinator.layer
+            val innerNodeLayer = innerCoordinator.layer.takeIf {
+                // emit the innerCoordinator only if it's different than current coordinator and
+                // this is the last node
+
+                // note: this logic will correctly handle the case where a Modifier.Node as the last
+                // element in the chain calls placeWithLayer. However, it does also cause an emit
+                // when .graphicsLayer is the last element in the chain as well - was previously
+                // depended upon by ui-tooling to avoid seeing the Crossfade layer.
+
+                // Going forward, as a contract, all layers will be emitted. And UI-tooling should
+                // not gain a new dependency on omitted layers.
+                val localChild = node.child
+                localChild === tail && node.coordinator !== localChild.coordinator
+            }
+            val layer = currentNodeLayer ?: innerNodeLayer
+            infoList += ModifierInfo(current[i++], coordinator, layer)
         }
         return infoList.asMutableList()
     }
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/ComposeScene.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/ComposeScene.desktop.kt
index 9fb410a..6399dc1 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/ComposeScene.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/ComposeScene.desktop.kt
@@ -62,6 +62,7 @@
         eventType,
         timeMillis,
         listOf(
+            @OptIn(ExperimentalComposeUiApi::class)
             PointerInputEventData(
                 PointerId(pointerId),
                 timeMillis,
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/input/pointer/TestPointerInputEventData.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/input/pointer/TestPointerInputEventData.skiko.kt
index b30311d..92eac76 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/input/pointer/TestPointerInputEventData.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/input/pointer/TestPointerInputEventData.skiko.kt
@@ -16,6 +16,7 @@
 
 package androidx.compose.ui.input.pointer
 
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.geometry.Offset
 
@@ -30,6 +31,7 @@
     val down: Boolean
 ) {
     internal fun toPointerInputEventData() =
+        @OptIn(ExperimentalComposeUiApi::class)
         PointerInputEventData(
             id,
             uptime,
diff --git a/constraintlayout/constraintlayout-compose/api/api_lint.ignore b/constraintlayout/constraintlayout-compose/api/api_lint.ignore
index 77dd380..33c2cfc 100644
--- a/constraintlayout/constraintlayout-compose/api/api_lint.ignore
+++ b/constraintlayout/constraintlayout-compose/api/api_lint.ignore
@@ -5,29 +5,11 @@
     Parameter type is concrete collection (`java.util.HashMap`); must be higher-level interface
 
 
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.compose.ui.Modifier, int, androidx.constraintlayout.compose.MotionLayoutState, androidx.constraintlayout.compose.MotionScene, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #0:
+KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, int, androidx.constraintlayout.compose.LayoutInformationReceiver, int, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #2:
     Parameter `modifier` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.compose.ui.Modifier, int, androidx.constraintlayout.compose.MotionLayoutState, androidx.constraintlayout.compose.MotionScene, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #1:
-    Parameter `optimizationLevel` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags>, androidx.constraintlayout.compose.LayoutInformationReceiver, int, java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag>, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #2:
-    Parameter `modifier` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags>, androidx.constraintlayout.compose.LayoutInformationReceiver, int, java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag>, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #3:
+KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, int, androidx.constraintlayout.compose.LayoutInformationReceiver, int, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #3:
     Parameter `transition` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags>, int, java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag>, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #2:
+KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, int, int, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #2:
     Parameter `modifier` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags>, int, java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag>, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #3:
+KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionLayoutKt#MotionLayout(androidx.constraintlayout.compose.ConstraintSet, androidx.constraintlayout.compose.ConstraintSet, androidx.compose.ui.Modifier, androidx.constraintlayout.compose.Transition, float, int, int, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit>) parameter #3:
     Parameter `transition` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionSceneScope#addConstraintSet(String, androidx.constraintlayout.compose.ConstraintSet) parameter #0:
-    Parameter `name` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionSceneScope#addTransition(String, androidx.constraintlayout.compose.Transition) parameter #0:
-    Parameter `name` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-KotlinDefaultParameterOrder: androidx.constraintlayout.compose.MotionSceneScope#transition(String, androidx.constraintlayout.compose.ConstraintSetRef, androidx.constraintlayout.compose.ConstraintSetRef, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.TransitionScope,kotlin.Unit>) parameter #0:
-    Parameter `name` has a default value and should come after all parameters without default values (except for a trailing lambda parameter)
-
-
-MethodNameUnits: androidx.constraintlayout.compose.TransitionScope#getDurationMs():
-    Expected method name units to be `Millis or Micros`, was `Ms` in `getDurationMs`
-
-
-MutableBareField: androidx.constraintlayout.compose.State#layoutDirection:
-    Bare field layoutDirection must be marked final, or moved behind accessors if mutable
diff --git a/constraintlayout/constraintlayout-compose/api/current.txt b/constraintlayout/constraintlayout-compose/api/current.txt
index 47442ef..3d50674 100644
--- a/constraintlayout/constraintlayout-compose/api/current.txt
+++ b/constraintlayout/constraintlayout-compose/api/current.txt
@@ -21,6 +21,7 @@
   }
 
   @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class ConstrainScope {
+    method public androidx.constraintlayout.compose.Dimension asDimension(float);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor);
     method public void centerHorizontallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
@@ -33,7 +34,7 @@
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
     method public float getAlpha();
-    method public androidx.constraintlayout.compose.Dimension getAsDimension(float);
+    method @Deprecated public androidx.constraintlayout.compose.Dimension getAsDimension(float);
     method public androidx.constraintlayout.compose.BaselineAnchorable getBaseline();
     method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
     method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
@@ -441,11 +442,11 @@
     enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags UNKNOWN;
   }
 
-  public enum MotionLayoutFlag {
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
+  @Deprecated public enum MotionLayoutFlag {
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
   }
 
   @kotlin.jvm.JvmInline public final value class Skip {
diff --git a/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt b/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt
index fb97584..92a3feb 100644
--- a/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt
+++ b/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt
@@ -56,6 +56,7 @@
   }
 
   @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class ConstrainScope {
+    method public androidx.constraintlayout.compose.Dimension asDimension(float);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor);
     method public void centerHorizontallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
@@ -68,7 +69,7 @@
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
     method public float getAlpha();
-    method public androidx.constraintlayout.compose.Dimension getAsDimension(float);
+    method @Deprecated public androidx.constraintlayout.compose.Dimension getAsDimension(float);
     method public androidx.constraintlayout.compose.BaselineAnchorable getBaseline();
     method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
     method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
@@ -334,6 +335,24 @@
     property public final androidx.constraintlayout.compose.CurveFit Spline;
   }
 
+  @androidx.constraintlayout.compose.ExperimentalMotionApi @kotlin.jvm.JvmInline public final value class DebugFlags {
+    ctor public DebugFlags(optional boolean showBounds, optional boolean showPaths, optional boolean showKeyPositions);
+    method public boolean getShowBounds();
+    method public boolean getShowKeyPositions();
+    method public boolean getShowPaths();
+    property public final boolean showBounds;
+    property public final boolean showKeyPositions;
+    property public final boolean showPaths;
+    field public static final androidx.constraintlayout.compose.DebugFlags.Companion Companion;
+  }
+
+  public static final class DebugFlags.Companion {
+    method public int getAll();
+    method public int getNone();
+    property public final int All;
+    property public final int None;
+  }
+
   public final class DesignElements {
     method public void define(String name, kotlin.jvm.functions.Function2<? super java.lang.String,? super java.util.HashMap<java.lang.String,java.lang.String>,kotlin.Unit> function);
     method public java.util.HashMap<java.lang.String,kotlin.jvm.functions.Function2<java.lang.String,java.util.HashMap<java.lang.String,java.lang.String>,kotlin.Unit>> getMap();
@@ -616,18 +635,18 @@
     enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags UNKNOWN;
   }
 
-  public enum MotionLayoutFlag {
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
+  @Deprecated public enum MotionLayoutFlag {
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
   }
 
   public final class MotionLayoutKt {
-    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, float progress, optional java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags> debug, optional int optimizationLevel, optional java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, float progress, optional androidx.compose.ui.Modifier modifier, optional String transitionName, optional java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags> debug, optional int optimizationLevel, optional java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, optional androidx.compose.ui.Modifier modifier, optional String? constraintSetName, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags> debug, optional int optimizationLevel, optional java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, optional kotlin.jvm.functions.Function0<kotlin.Unit>? finishedAnimationListener, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, float progress, optional java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags> debug, optional androidx.constraintlayout.compose.LayoutInformationReceiver? informationReceiver, optional int optimizationLevel, optional java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, float progress, optional int debugFlags, optional int optimizationLevel, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, float progress, optional androidx.compose.ui.Modifier modifier, optional String transitionName, optional int debugFlags, optional int optimizationLevel, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, optional androidx.compose.ui.Modifier modifier, optional String? constraintSetName, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional int debugFlags, optional int optimizationLevel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? finishedAnimationListener, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, float progress, optional int debugFlags, optional androidx.constraintlayout.compose.LayoutInformationReceiver? informationReceiver, optional int optimizationLevel, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, androidx.constraintlayout.compose.MotionLayoutState motionLayoutState, optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
   }
 
diff --git a/constraintlayout/constraintlayout-compose/api/restricted_current.txt b/constraintlayout/constraintlayout-compose/api/restricted_current.txt
index 35fb12d..6038cb7 100644
--- a/constraintlayout/constraintlayout-compose/api/restricted_current.txt
+++ b/constraintlayout/constraintlayout-compose/api/restricted_current.txt
@@ -28,6 +28,7 @@
   }
 
   @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class ConstrainScope {
+    method public androidx.constraintlayout.compose.Dimension asDimension(float);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor);
     method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor);
     method public void centerHorizontallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
@@ -40,7 +41,7 @@
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
     method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
     method public float getAlpha();
-    method public androidx.constraintlayout.compose.Dimension getAsDimension(float);
+    method @Deprecated public androidx.constraintlayout.compose.Dimension getAsDimension(float);
     method public androidx.constraintlayout.compose.BaselineAnchorable getBaseline();
     method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
     method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
@@ -557,16 +558,16 @@
     enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags UNKNOWN;
   }
 
-  public enum MotionLayoutFlag {
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
-    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
+  @Deprecated public enum MotionLayoutFlag {
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method @Deprecated public static androidx.constraintlayout.compose.MotionLayoutFlag[] values();
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
   }
 
   public final class MotionLayoutKt {
-    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, optional androidx.compose.ui.Modifier modifier, optional String? constraintSetName, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional androidx.constraintlayout.compose.MotionLayoutDebugFlags debugFlag, optional int optimizationLevel, optional java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, optional kotlin.jvm.functions.Function0<kotlin.Unit>? finishedAnimationListener, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, float progress, String transitionName, int optimizationLevel, java.util.Set<? extends androidx.constraintlayout.compose.MotionLayoutFlag> motionLayoutFlags, java.util.EnumSet<androidx.constraintlayout.compose.MotionLayoutDebugFlags> debug, androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, optional androidx.compose.ui.Modifier modifier, optional String? constraintSetName, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional int debugFlags, optional int optimizationLevel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? finishedAnimationListener, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, float progress, String transitionName, int optimizationLevel, int debugFlags, androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, String transitionName, androidx.constraintlayout.compose.MotionLayoutStateImpl motionLayoutState, int optimizationLevel, androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static inline void MotionLayoutCore(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, androidx.constraintlayout.compose.TransitionImpl? transition, androidx.constraintlayout.compose.MotionProgress motionProgress, androidx.constraintlayout.compose.LayoutInformationReceiver? informationReceiver, int optimizationLevel, boolean showBounds, boolean showPaths, boolean showKeyPositions, androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.constraintlayout.compose.MotionLayoutScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static void UpdateWithForcedIfNoUserChange(androidx.constraintlayout.compose.MotionProgress motionProgress, androidx.constraintlayout.compose.LayoutInformationReceiver? informationReceiver);
diff --git a/constraintlayout/constraintlayout-compose/build.gradle b/constraintlayout/constraintlayout-compose/build.gradle
index 4467da8..639aa60 100644
--- a/constraintlayout/constraintlayout-compose/build.gradle
+++ b/constraintlayout/constraintlayout-compose/build.gradle
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
+import androidx.build.Publish
 
 plugins {
     id("AndroidXPlugin")
@@ -22,49 +24,77 @@
     id("AndroidXComposePlugin")
 }
 
-androidXMultiplatform {
-    android()
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-    sourceSets {
-        commonMain {
-            dependencies {
+dependencies {
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        implementation(project(":compose:ui:ui"))
+        implementation(project(":compose:ui:ui-unit"))
+        implementation(project(":compose:ui:ui-util"))
+        implementation(project(":compose:foundation:foundation"))
+        implementation(project(":compose:foundation:foundation-layout"))
+
+        implementation(project(":constraintlayout:constraintlayout-core"))
+
+        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation(project(":compose:ui:ui-test"))
+        androidTestImplementation(project(":compose:ui:ui-test-junit4"))
+        androidTestImplementation(project(":compose:ui:ui-test-manifest"))
+        androidTestImplementation(project(":activity:activity"))
+
+        androidTestImplementation(libs.kotlinTest)
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+
+        lintPublish(project(":constraintlayout:constraintlayout-compose-lint"))
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
+//                implementation(libs.kotlinStdlibCommon)
+
                 implementation(project(":compose:ui:ui"))
                 implementation("androidx.compose.ui:ui-unit:1.4.0-beta02")
                 implementation("androidx.compose.ui:ui-util:1.4.0-beta02")
                 implementation("androidx.compose.foundation:foundation:1.4.0-beta02")
                 implementation("androidx.compose.foundation:foundation-layout:1.4.0-beta02")
                 implementation(project(":constraintlayout:constraintlayout-core"))
+
             }
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependencies {
-            }
-        }
-
-
-        androidMain {
-            dependsOn(commonMain)
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
                 implementation("androidx.core:core-ktx:1.5.0")
             }
-        }
 
-        jvmTest {
-            dependencies {
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependencies {
+            // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
+            //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
+            //  level dependencies block instead:
+            //  `dependencies { testImplementation(libs.robolectric) }`
+            androidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+            }
+
+            androidAndroidTest.dependencies {
                 implementation(libs.kotlinTest)
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
@@ -77,27 +107,9 @@
                 implementation(project(":compose:test-utils"))
             }
         }
-
-
-        // TODO(b/214407011): These dependencies leak into instrumented tests as well. If you
-        //  need to add Robolectric (which must be kept out of androidAndroidTest), use a top
-        //  level dependencies block instead:
-        //  `dependencies { testImplementation(libs.robolectric) }`
-        androidTest {
-            dependsOn(jvmTest)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-            }
-        }
     }
 }
 
-dependencies {
-    lintPublish(project(":constraintlayout:constraintlayout-compose-lint"))
-}
-
 androidx {
     name = "Android ConstraintLayout Compose Library"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/MotionLayoutActivity.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/MotionLayoutActivity.kt
index 24ae735..4e015c9 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/MotionLayoutActivity.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/MotionLayoutActivity.kt
@@ -17,18 +17,22 @@
 package androidx.constraintlayout.compose.integration.macrobenchmark.target
 
 import android.os.Bundle
+import android.view.Choreographer
+import android.view.View
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.integration.macrobenchmark.target.motionlayout.newmessage.NewMotionMessagePreview
-import androidx.compose.integration.macrobenchmark.target.motionlayout.newmessage.NewMotionMessagePreviewWithDsl
-import androidx.compose.integration.macrobenchmark.target.motionlayout.toolbar.MotionCollapseToolbarPreview
+import androidx.constraintlayout.compose.integration.macrobenchmark.target.newmessage.NewMotionMessagePreview
+import androidx.constraintlayout.compose.integration.macrobenchmark.target.newmessage.NewMotionMessagePreviewWithDsl
+import androidx.constraintlayout.compose.integration.macrobenchmark.target.toolbar.MotionCollapseToolbarPreview
 import androidx.compose.material.MaterialTheme
 import androidx.compose.material.Surface
+import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.testTagsAsResourceId
+import androidx.constraintlayout.compose.integration.macrobenchmark.target.graphs.DynamicGraphsPreview
 
 class MotionLayoutActivity : ComponentActivity() {
 
@@ -57,6 +61,9 @@
                         "CollapsibleToolbar" -> {
                             MotionCollapseToolbarPreview()
                         }
+                        "DynamicGraphs" -> {
+                            DynamicGraphsPreview()
+                        }
                         else -> {
                             throw IllegalArgumentException("No Composable with name: $name")
                         }
@@ -64,5 +71,22 @@
                 }
             }
         }
+        launchIdlenessTracking()
+    }
+
+    // Copied from LazyColumnActivity.kt
+    private fun ComponentActivity.launchIdlenessTracking() {
+        val contentView: View = findViewById(android.R.id.content)
+        val callback: Choreographer.FrameCallback = object : Choreographer.FrameCallback {
+            override fun doFrame(frameTimeNanos: Long) {
+                if (Recomposer.runningRecomposers.value.any { it.hasPendingWork }) {
+                    contentView.contentDescription = "COMPOSE-BUSY"
+                } else {
+                    contentView.contentDescription = "COMPOSE-IDLE"
+                }
+                Choreographer.getInstance().postFrameCallback(this)
+            }
+        }
+        Choreographer.getInstance().postFrameCallback(callback)
     }
 }
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/graphs/DynamicGraphs.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/graphs/DynamicGraphs.kt
new file mode 100644
index 0000000..1ba89a0
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/graphs/DynamicGraphs.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalMotionApi::class)
+
+package androidx.constraintlayout.compose.integration.macrobenchmark.target.graphs
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+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.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.constraintlayout.compose.Dimension
+import androidx.constraintlayout.compose.ExperimentalMotionApi
+import androidx.constraintlayout.compose.MotionLayout
+import androidx.constraintlayout.compose.MotionScene
+import kotlin.random.Random
+
+/**
+ * Shows how to use MotionLayout to have animated graphs in a LazyColumn, where each graph is
+ * animated as it's revealed.
+ *
+ * Demonstrates how to dynamically create constraints based on input. See [DynamicGraph]. Where
+ * constraints are created to lay out the given values into a single graph layout.
+ */
+@Preview(group = "scroll", device = "spec:shape=Normal,width=480,height=800,unit=dp,dpi=440")
+@Composable
+fun DynamicGraphsPreview(modifier: Modifier = Modifier) {
+    val graphs = remember {
+        val list = mutableListOf<List<Float>>()
+        repeat(300) {
+            val values = FloatArray(10) { Random.nextInt(100).toFloat() + 10f }.asList()
+            list.add(values)
+        }
+        return@remember list
+    }
+    LazyColumn(modifier.testTag("LazyColumn")) {
+        items(graphs.size) {
+            Box(
+                modifier = Modifier
+                    .padding(3.dp)
+                    .height(200.dp)
+            ) {
+                DynamicGraph(graphs[it])
+            }
+        }
+    }
+}
+
+@Preview(group = "scroll", device = "spec:shape=Normal,width=480,height=800,unit=dp,dpi=440")
+@Composable
+private fun DynamicGraph(
+    values: List<Float> = listOf<Float>(12f, 32f, 21f, 32f, 2f),
+    max: Int = 100
+) {
+    val scene = remember {
+        val scale = values.map { (it * 0.8f) / max }
+        val count = values.size
+        val widthPercent = 1 / (count * 2f)
+
+        MotionScene {
+            val cols = Array(count) { i -> createRefFor("foo$i") }
+            val start1 = constraintSet {
+                createHorizontalChain(elements = cols)
+                cols.forEach {
+                    constrain(it) {
+                        width = Dimension.percent(widthPercent)
+                        height = Dimension.value(1.dp)
+                        bottom.linkTo(parent.bottom, 16.dp)
+                    }
+                }
+            }
+
+            val end1 = constraintSet {
+                createHorizontalChain(elements = cols)
+                cols.forEachIndexed { i, col ->
+                    constrain(col) {
+                        width = Dimension.percent(widthPercent)
+                        height = Dimension.percent(scale[i])
+                        bottom.linkTo(parent.bottom, 16.dp)
+                    }
+                }
+            }
+            defaultTransition(start1, end1)
+        }
+    }
+    var animateToEnd by remember { mutableStateOf(true) }
+    val progress = remember { Animatable(0f) }
+
+    // Animate on reveal
+    LaunchedEffect(animateToEnd) {
+        progress.animateTo(
+            if (animateToEnd) 1f else 0f,
+            animationSpec = tween(800)
+        )
+    }
+
+    MotionLayout(
+        modifier = Modifier
+            .background(Color(0xFF221010))
+            .fillMaxSize()
+            .clickable { animateToEnd = !animateToEnd }
+            .padding(1.dp),
+        motionScene = scene,
+        progress = progress.value
+    ) {
+        for (i in 0..values.size) {
+            Box(
+                modifier = Modifier
+                    .layoutId("foo$i")
+                    .clip(RoundedCornerShape(20.dp))
+                    .background(Color.hsv(i * 240f / values.size, 0.6f, 0.6f))
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessage.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessage.kt
index 8d144a9..75c0dc8 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessage.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessage.kt
@@ -16,7 +16,7 @@
 
 @file:OptIn(ExperimentalMotionApi::class)
 
-package androidx.compose.integration.macrobenchmark.target.motionlayout.newmessage
+package androidx.constraintlayout.compose.integration.macrobenchmark.target.newmessage
 
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.layout.Arrangement
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessageState.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessageState.kt
index 677182e..0fb0062 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessageState.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/newmessage/NewMessageState.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.integration.macrobenchmark.target.motionlayout.newmessage
+package androidx.constraintlayout.compose.integration.macrobenchmark.target.newmessage
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/toolbar/CollapsibleToolbar.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/toolbar/CollapsibleToolbar.kt
index 50ab5bc..3fe6074 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/toolbar/CollapsibleToolbar.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark-target/src/main/java/androidx/constraintlayout/compose/integration/macrobenchmark/target/toolbar/CollapsibleToolbar.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.integration.macrobenchmark.target.motionlayout.toolbar
+package androidx.constraintlayout.compose.integration.macrobenchmark.target.toolbar
 
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
diff --git a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
index d15fad9..73f439c 100644
--- a/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
+++ b/constraintlayout/constraintlayout-compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/constraintlayout/compose/integration/macrobenchmark/MotionLayoutBenchmark.kt
@@ -24,6 +24,8 @@
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
 import kotlin.math.roundToInt
 import org.junit.Rule
 import org.junit.Test
@@ -55,10 +57,49 @@
     fun messageJson() = benchmarkRule.testNewMessage(NewMessageMode.Json)
 
     @Test
-    fun collapsibleToolbar() = benchmarkRule.testCollapsibleToolbar()
+    fun collapsibleToolbar() = benchmarkRule.motionBenchmark("CollapsibleToolbar") {
+        val column = device.findObject(By.res("LazyColumn"))
+        val bounds = column.visibleBounds
+
+        // Margin to reduce the amount of pixels scrolled and avoid the navigation pill
+        val vMargin = (bounds.height() * 0.2f).roundToInt()
+        val x = (bounds.width() * 0.5f).roundToInt()
+        val y1 = bounds.bottom - vMargin
+        val y2 = bounds.top + vMargin
+
+        // Scroll down
+        device.swipe(x, y1, x, y2, 50)
+        device.waitForIdle()
+
+        // Scroll up
+        device.swipe(x, y2, x, y1, 50)
+        device.waitForIdle()
+    }
 
     /**
-     * The base method to benchmark FrameTimings of a Composable from the macrobenchmark-app module.
+     * LazyList based layout, where every item is a MotionLayout Composable and are animated as they
+     * are revealed.
+     */
+    @Test
+    fun dynamicGraphs() = benchmarkRule.motionBenchmark("DynamicGraphs") {
+        val column = device.findObject(By.res("LazyColumn"))
+        val bounds = column.visibleBounds
+
+        // Margin to avoid swiping the navigation pill
+        val vMargin = (bounds.height() * 0.1f).roundToInt()
+        val x = (bounds.width() * 0.5f).roundToInt()
+        val y1 = bounds.bottom - vMargin
+        val y2 = bounds.top + vMargin
+
+        repeat(5) {
+            // Fast swipe upwards, to scroll down through multiple animated items at a time
+            device.swipe(x, y1, x, y2, 6)
+            device.waitForComposeIdle()
+        }
+    }
+
+    /**
+     * The base method to benchmark FrameTimings of a Composable from the macrobenchmark-target module.
      *
      * [composableName] should be a registered Composable in **MotionLayoutBenchmarkActivity**
      *
@@ -87,32 +128,13 @@
                 intent.putExtra("ComposableName", composableName)
                 startActivityAndWait(intent)
                 device.waitForIdle()
+                device.waitForComposeIdle()
                 setupBlock()
             },
             measureBlock = measureBlock
         )
     }
 
-    private fun MacrobenchmarkRule.testCollapsibleToolbar() =
-        motionBenchmark("CollapsibleToolbar") {
-            val column = device.findObject(By.res("LazyColumn"))
-            val bounds = column.visibleBounds
-
-            // Margin to reduce the amount of pixels scrolled
-            val vMargin = (bounds.height() * 0.2f).roundToInt()
-            val x = (bounds.width() * 0.5f).roundToInt()
-            val y1 = bounds.bottom - vMargin
-            val y2 = bounds.top + vMargin
-
-            // Swipe down
-            device.swipe(x, y1, x, y2, 50)
-            device.waitForIdle()
-
-            // Swipe up
-            device.swipe(x, y2, x, y1, 50)
-            device.waitForIdle()
-        }
-
     private fun MacrobenchmarkRule.testNewMessage(
         mode: NewMessageMode
     ) {
@@ -138,4 +160,8 @@
         Json("NewMessageJson"),
         Dsl("NewMessageDsl")
     }
+
+    private fun UiDevice.waitForComposeIdle(timeoutMs: Long = 3000) {
+        wait(Until.findObject(By.desc("COMPOSE-IDLE")), timeoutMs)
+    }
 }
diff --git a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/ConstraintLayoutTest.kt b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/ConstraintLayoutTest.kt
index f790ba9..b418a5d 100644
--- a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/ConstraintLayoutTest.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/ConstraintLayoutTest.kt
@@ -1954,14 +1954,14 @@
                     val (box0, box1, box2) = createRefsFor("box0", "box1")
 
                     constrain(box0, box1) {
-                        width = boxSize.toDp().asDimension
-                        height = boxSize.toDp().asDimension
+                        width = boxSize.toDp().asDimension()
+                        height = boxSize.toDp().asDimension()
                         top.linkTo(parent.top, margin.toDp())
                         start.linkTo(parent.start, margin.toDp())
                     }
                     constrain(box2) {
-                        width = boxSize.toDp().asDimension
-                        height = boxSize.toDp().asDimension
+                        width = boxSize.toDp().asDimension()
+                        height = boxSize.toDp().asDimension()
 
                         top.linkTo(box0.bottom)
                         start.linkTo(box0.end)
@@ -2399,8 +2399,8 @@
                 Box(
                     Modifier
                         .constrainAs(boxRef) {
-                            width = boxSizePx.toDp().asDimension
-                            height = boxSizePx.toDp().asDimension
+                            width = boxSizePx.toDp().asDimension()
+                            height = boxSizePx.toDp().asDimension()
                             centerTo(parent)
 
                             translationX = translationXPx.toDp()
@@ -2505,8 +2505,8 @@
                     Modifier
                         .testTag("box1")
                         .constrainAs(box1) {
-                            width = boxSizePx.toDp().asDimension
-                            height = boxSizePx.toDp().asDimension
+                            width = boxSizePx.toDp().asDimension()
+                            height = boxSizePx.toDp().asDimension()
 
                             top.linkTo(box0.top)
                             start.linkTo(box0.end)
diff --git a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/FlowTest.kt b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/FlowTest.kt
index f226f10..2bdac98 100644
--- a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/FlowTest.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/FlowTest.kt
@@ -253,7 +253,7 @@
             )
 
             constrain(flow) {
-                width = flowWidth.toDp().asDimension
+                width = flowWidth.toDp().asDimension()
 
                 top.linkTo(parent.top)
                 start.linkTo(parent.start)
@@ -262,8 +262,8 @@
                 constrain(itemRef) {
                     val widthPx =
                         if (index == indexOfBigItem) baseBoxSizePx.times(2) else baseBoxSizePx
-                    width = widthPx.toDp().asDimension
-                    height = baseBoxSizePx.toDp().asDimension
+                    width = widthPx.toDp().asDimension()
+                    height = baseBoxSizePx.toDp().asDimension()
                 }
             }
         }
@@ -341,7 +341,7 @@
             )
 
             constrain(flow) {
-                height = flowHeight.toDp().asDimension
+                height = flowHeight.toDp().asDimension()
 
                 top.linkTo(parent.top)
                 start.linkTo(parent.start)
@@ -350,8 +350,8 @@
                 constrain(itemRef) {
                     val widthPx =
                         if (index == indexOfBigItem) baseBoxSizePx.times(2) else baseBoxSizePx
-                    height = widthPx.toDp().asDimension
-                    width = baseBoxSizePx.toDp().asDimension
+                    height = widthPx.toDp().asDimension()
+                    width = baseBoxSizePx.toDp().asDimension()
                 }
             }
         }
diff --git a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
index 7e84a3d..0098c1f 100644
--- a/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidAndroidTest/kotlin/androidx/constraintlayout/compose/MotionLayoutTest.kt
@@ -67,10 +67,12 @@
 import androidx.compose.ui.unit.IntRect
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
 import androidx.compose.ui.unit.round
 import androidx.compose.ui.unit.roundToIntRect
 import androidx.compose.ui.unit.size
 import androidx.compose.ui.unit.sp
+import androidx.compose.ui.unit.width
 import androidx.constraintlayout.compose.test.R
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -316,8 +318,8 @@
             val circleRef = createRefFor("circle")
             val aCSetRef = constraintSet {
                 constrain(circleRef) {
-                    width = rootHeightPx.toDp().asDimension
-                    height = rootHeightPx.toDp().asDimension
+                    width = rootHeightPx.toDp().asDimension()
+                    height = rootHeightPx.toDp().asDimension()
                     centerVerticallyTo(parent)
                     start.linkTo(parent.start)
                 }
@@ -325,7 +327,7 @@
             val bCSetRef = constraintSet {
                 constrain(circleRef) {
                     width = Dimension.fillToConstraints
-                    height = rootHeightPx.toDp().asDimension
+                    height = rootHeightPx.toDp().asDimension()
                     centerTo(parent)
                 }
             }
@@ -427,8 +429,8 @@
                     defaultTransition(
                         from = constraintSet {
                             constrain(box) {
-                                width = boxWidthStartPx.toDp().asDimension
-                                height = boxHeight.toDp().asDimension
+                                width = boxWidthStartPx.toDp().asDimension()
+                                height = boxHeight.toDp().asDimension()
 
                                 top.linkTo(parent.top)
                                 centerHorizontallyTo(parent)
@@ -436,8 +438,8 @@
                         },
                         to = constraintSet {
                             constrain(box) {
-                                width = boxWidthEndPx.toDp().asDimension
-                                height = boxHeight.toDp().asDimension
+                                width = boxWidthEndPx.toDp().asDimension()
+                                height = boxHeight.toDp().asDimension()
 
                                 centerHorizontallyTo(parent)
                                 bottom.linkTo(parent.bottom)
@@ -599,6 +601,64 @@
         }
     }
 
+    @Test
+    fun testRemeasureOnContentChanged() {
+        val progress = mutableStateOf(0f)
+        val textContent = mutableStateOf("Foo")
+
+        rule.setContent {
+            WithConsistentTextStyle {
+                MotionLayout(
+                    modifier = Modifier
+                        .size(300.dp)
+                        .background(Color.LightGray),
+                    motionScene = MotionScene {
+                        // Text at wrap_content, animated from top of the layout to the bottom
+                        val textRef = createRefFor("text")
+                        defaultTransition(
+                            from = constraintSet {
+                                constrain(textRef) {
+                                    centerHorizontallyTo(parent)
+                                    centerVerticallyTo(parent, 0f)
+                                }
+                            },
+                            to = constraintSet {
+                                constrain(textRef) {
+                                    centerHorizontallyTo(parent)
+                                    centerVerticallyTo(parent, 1f)
+                                }
+                            }
+                        )
+                    },
+                    progress = progress.value
+                ) {
+                    Text(
+                        text = textContent.value,
+                        fontSize = 10.sp,
+                        modifier = Modifier.layoutTestId("text")
+                    )
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        var actualTextSize = rule.onNodeWithTag("text").getUnclippedBoundsInRoot()
+        assertEquals(18, actualTextSize.width.value.roundToInt())
+        assertEquals(14, actualTextSize.height.value.roundToInt())
+
+        progress.value = 0.5f
+        rule.waitForIdle()
+        actualTextSize = rule.onNodeWithTag("text").getUnclippedBoundsInRoot()
+        assertEquals(18, actualTextSize.width.value.roundToInt())
+        assertEquals(14, actualTextSize.height.value.roundToInt())
+
+        textContent.value = "FooBar"
+        rule.waitForIdle()
+        actualTextSize = rule.onNodeWithTag("text").getUnclippedBoundsInRoot()
+        assertEquals(36, actualTextSize.width.value.roundToInt())
+        assertEquals(14, actualTextSize.height.value.roundToInt())
+    }
+
     private fun Color.toHexString(): String = toArgb().toUInt().toString(16)
 }
 
@@ -606,15 +666,7 @@
 @Composable
 private fun CustomTextSize(modifier: Modifier, progress: Float) {
     val context = LocalContext.current
-    @Suppress("DEPRECATION")
-    CompositionLocalProvider(
-        LocalDensity provides Density(1f, 1f),
-        LocalTextStyle provides TextStyle(
-            fontFamily = FontFamily.Monospace,
-            fontWeight = FontWeight.Normal,
-            platformStyle = PlatformTextStyle(includeFontPadding = true)
-        )
-    ) {
+    WithConsistentTextStyle {
         MotionLayout(
             motionScene = MotionScene(
                 content = context
@@ -652,4 +704,27 @@
             )
         }
     }
+}
+
+/**
+ * Provides composition locals that help making Text produce consistent measurements across multiple
+ * devices.
+ *
+ * Be aware that this makes it so that 1.dp = 1px. So the layout will look significantly different
+ * than expected.
+ */
+@Composable
+private fun WithConsistentTextStyle(
+    content: @Composable () -> Unit
+) {
+    @Suppress("DEPRECATION")
+    CompositionLocalProvider(
+        LocalDensity provides Density(1f, 1f),
+        LocalTextStyle provides TextStyle(
+            fontFamily = FontFamily.Monospace,
+            fontWeight = FontWeight.Normal,
+            platformStyle = PlatformTextStyle(includeFontPadding = true)
+        ),
+        content = content
+    )
 }
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstrainScope.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstrainScope.kt
index 30c52cf..6d9d6ae 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstrainScope.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstrainScope.kt
@@ -448,9 +448,17 @@
      *
      * @see Dimension.value
      */
+    @Deprecated("Prefer `Dp.asDimension()`.", ReplaceWith("this.asDimension()"))
     val Dp.asDimension: Dimension
         get() = Dimension.value(this)
 
+    /**
+     * Convenience extension method to parse a [Dp] as a [Dimension] object.
+     *
+     * @see Dimension.value
+     */
+    fun Dp.asDimension(): Dimension = Dimension.value(this)
+
     private inner class DimensionProperty(initialValue: Dimension) :
         ObservableProperty<Dimension>(initialValue) {
         override fun afterChange(property: KProperty<*>, oldValue: Dimension, newValue: Dimension) {
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
index 92890ea..e7c9df02 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/ConstraintLayout.kt
@@ -1362,7 +1362,7 @@
         state.mParent.height.apply(state, root, ConstraintWidget.VERTICAL)
         // Build constraint set and apply it to the state.
         state.rootIncomingConstraints = constraints
-        state.isLtr = layoutDirection == LayoutDirection.Ltr
+        state.isRtl = layoutDirection == LayoutDirection.Rtl
         resetMeasureState()
         if (constraintSet.isDirty(measurables)) {
             state.reset()
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionCarousel.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionCarousel.kt
index ba68ca1..2656198 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionCarousel.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionCarousel.kt
@@ -238,7 +238,6 @@
     MotionLayout(motionScene = motionScene,
         transitionName = transitionName.value,
         progress = mprogress,
-        motionLayoutFlags = setOf(MotionLayoutFlag.FullMeasure), // TODO: only apply as needed
         modifier = Modifier
             .fillMaxSize()
             .background(Color.White)
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionLayout.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionLayout.kt
index b961b63..61b5b95 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionLayout.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionLayout.kt
@@ -50,15 +50,17 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.constraintlayout.core.widgets.Optimizer
-import java.util.EnumSet
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.launch
 
 /**
  * Measure flags for MotionLayout
  */
+@Deprecated("Unnecessary, MotionLayout remeasures when its content changes.")
 enum class MotionLayoutFlag(@Suppress("UNUSED_PARAMETER") value: Long) {
     Default(0),
+
+    @Suppress("unused")
     FullMeasure(1)
 }
 
@@ -72,7 +74,6 @@
  * Layout that interpolate its children layout given two sets of constraint and
  * a progress (from 0 to 1)
  */
-@Suppress("UNUSED_PARAMETER")
 @ExperimentalMotionApi
 @Composable
 inline fun MotionLayout(
@@ -81,13 +82,11 @@
     modifier: Modifier = Modifier,
     transition: Transition? = null,
     progress: Float,
-    debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
+    debugFlags: DebugFlags = DebugFlags.None,
     optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
-    motionLayoutFlags: Set<MotionLayoutFlag> = setOf<MotionLayoutFlag>(),
     crossinline content: @Composable MotionLayoutScope.() -> Unit
 ) {
     val motionProgress = createAndUpdateMotionProgress(progress = progress)
-    val showDebug = debug.firstOrNull() == MotionLayoutDebugFlags.SHOW_ALL
     MotionLayoutCore(
         start = start,
         end = end,
@@ -95,9 +94,9 @@
         motionProgress = motionProgress,
         informationReceiver = null,
         optimizationLevel = optimizationLevel,
-        showBounds = showDebug,
-        showPaths = showDebug,
-        showKeyPositions = showDebug,
+        showBounds = debugFlags.showBounds,
+        showPaths = debugFlags.showPaths,
+        showKeyPositions = debugFlags.showKeyPositions,
         modifier = modifier,
         content = content
     )
@@ -114,19 +113,17 @@
     progress: Float,
     modifier: Modifier = Modifier,
     transitionName: String = "default",
-    debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
+    debugFlags: DebugFlags = DebugFlags.None,
     optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
-    motionLayoutFlags: Set<MotionLayoutFlag> = setOf<MotionLayoutFlag>(),
     crossinline content: @Composable (MotionLayoutScope.() -> Unit),
 ) {
     MotionLayoutCore(
         motionScene = motionScene,
         progress = progress,
-        debug = debug,
+        debugFlags = debugFlags,
         modifier = modifier,
         optimizationLevel = optimizationLevel,
         transitionName = transitionName,
-        motionLayoutFlags = motionLayoutFlags,
         content = content
     )
 }
@@ -150,9 +147,8 @@
     modifier: Modifier = Modifier,
     constraintSetName: String? = null,
     animationSpec: AnimationSpec<Float> = tween(),
-    debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
+    debugFlags: DebugFlags = DebugFlags.None,
     optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
-    motionLayoutFlags: Set<MotionLayoutFlag> = setOf<MotionLayoutFlag>(),
     noinline finishedAnimationListener: (() -> Unit)? = null,
     crossinline content: @Composable (MotionLayoutScope.() -> Unit)
 ) {
@@ -160,16 +156,14 @@
         motionScene = motionScene,
         constraintSetName = constraintSetName,
         animationSpec = animationSpec,
-        debugFlag = debug.firstOrNull() ?: MotionLayoutDebugFlags.NONE,
+        debugFlags = debugFlags,
         modifier = modifier,
         optimizationLevel = optimizationLevel,
         finishedAnimationListener = finishedAnimationListener,
-        motionLayoutFlags = motionLayoutFlags,
         content = content
     )
 }
 
-@Suppress("UNUSED_PARAMETER")
 @ExperimentalMotionApi
 @Composable
 inline fun MotionLayout(
@@ -178,14 +172,12 @@
     modifier: Modifier = Modifier,
     transition: Transition? = null,
     progress: Float,
-    debug: EnumSet<MotionLayoutDebugFlags> = EnumSet.of(MotionLayoutDebugFlags.NONE),
+    debugFlags: DebugFlags = DebugFlags.None,
     informationReceiver: LayoutInformationReceiver? = null,
     optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
-    motionLayoutFlags: Set<MotionLayoutFlag> = setOf<MotionLayoutFlag>(),
     crossinline content: @Composable (MotionLayoutScope.() -> Unit)
 ) {
     val motionProgress = createAndUpdateMotionProgress(progress = progress)
-    val showDebug = debug.firstOrNull() == MotionLayoutDebugFlags.SHOW_ALL
     MotionLayoutCore(
         start = start,
         end = end,
@@ -193,9 +185,9 @@
         motionProgress = motionProgress,
         informationReceiver = informationReceiver,
         optimizationLevel = optimizationLevel,
-        showBounds = showDebug,
-        showPaths = showDebug,
-        showKeyPositions = showDebug,
+        showBounds = debugFlags.showBounds,
+        showPaths = debugFlags.showPaths,
+        showKeyPositions = debugFlags.showKeyPositions,
         modifier = modifier,
         content = content
     )
@@ -204,16 +196,15 @@
 @ExperimentalMotionApi
 @PublishedApi
 @Composable
-@Suppress("UnavailableSymbol", "UNUSED_PARAMETER")
+@Suppress("UnavailableSymbol")
 internal inline fun MotionLayoutCore(
     @Suppress("HiddenTypeParameter")
     motionScene: MotionScene,
     modifier: Modifier = Modifier,
     constraintSetName: String? = null,
     animationSpec: AnimationSpec<Float> = tween(),
-    debugFlag: MotionLayoutDebugFlags = MotionLayoutDebugFlags.NONE,
+    debugFlags: DebugFlags = DebugFlags.None,
     optimizationLevel: Int = Optimizer.OPTIMIZATION_STANDARD,
-    motionLayoutFlags: Set<MotionLayoutFlag> = setOf<MotionLayoutFlag>(),
     noinline finishedAnimationListener: (() -> Unit)? = null,
     @Suppress("HiddenTypeParameter")
     crossinline content: @Composable (MotionLayoutScope.() -> Unit)
@@ -293,9 +284,9 @@
         motionProgress = motionProgress,
         informationReceiver = motionScene as? LayoutInformationReceiver,
         optimizationLevel = optimizationLevel,
-        showBounds = debugFlag == MotionLayoutDebugFlags.SHOW_ALL,
-        showPaths = debugFlag == MotionLayoutDebugFlags.SHOW_ALL,
-        showKeyPositions = debugFlag == MotionLayoutDebugFlags.SHOW_ALL,
+        showBounds = debugFlags.showBounds,
+        showPaths = debugFlags.showPaths,
+        showKeyPositions = debugFlags.showKeyPositions,
         modifier = modifier,
         content = content
     )
@@ -311,8 +302,7 @@
     progress: Float,
     transitionName: String,
     optimizationLevel: Int,
-    motionLayoutFlags: Set<MotionLayoutFlag>,
-    debug: EnumSet<MotionLayoutDebugFlags>,
+    debugFlags: DebugFlags,
     modifier: Modifier,
     @Suppress("HiddenTypeParameter")
     crossinline content: @Composable MotionLayoutScope.() -> Unit,
@@ -338,11 +328,10 @@
         end = end,
         transition = transition,
         progress = progress,
-        debug = debug,
+        debugFlags = debugFlags,
         informationReceiver = motionScene as? LayoutInformationReceiver,
         modifier = modifier,
         optimizationLevel = optimizationLevel,
-        motionLayoutFlags = motionLayoutFlags,
         content = content
     )
 }
@@ -958,4 +947,78 @@
      * states.
      */
     Content
+}
+
+/**
+ * Flags to use with MotionLayout to enable visual debugging.
+ *
+ * @property showBounds
+ * @property showPaths
+ * @property showKeyPositions
+ *
+ * @see None
+ * @see All
+ */
+@ExperimentalMotionApi
+@JvmInline
+value class DebugFlags internal constructor(private val flags: Int) {
+    /**
+     * @param showBounds Whether to show the bounds of widgets at the start and end of the current transition.
+     * @param showPaths Whether to show the paths each widget will take through the current transition.
+     * @param showKeyPositions Whether to show a diamond icon representing KeyPositions defined for each widget along the path.
+     */
+    constructor(
+        showBounds: Boolean = false,
+        showPaths: Boolean = false,
+        showKeyPositions: Boolean = false
+    ) : this(
+        (if (showBounds) BOUNDS_FLAG else 0) or
+            (if (showPaths) PATHS_FLAG else 0) or
+            (if (showKeyPositions) KEY_POSITIONS_FLAG else 0)
+    )
+
+    /**
+     * When enabled, shows the bounds of widgets at the start and end of the current transition.
+     */
+    val showBounds: Boolean
+        get() = flags and BOUNDS_FLAG > 0
+
+    /**
+     * When enabled, shows the paths each widget will take through the current transition.
+     */
+    val showPaths: Boolean
+        get() = flags and PATHS_FLAG > 0
+
+    /**
+     *
+     * When enabled, shows a diamond icon representing KeyPositions defined for each widget along
+     * the path.
+     */
+    val showKeyPositions: Boolean
+        get() = flags and KEY_POSITIONS_FLAG > 0
+
+    override fun toString(): String =
+        "DebugFlags(" +
+            "showBounds = $showBounds, " +
+            "showPaths = $showPaths, " +
+            "showKeyPositions = $showKeyPositions" +
+            ")"
+
+    companion object {
+        private const val BOUNDS_FLAG = 1
+        private const val PATHS_FLAG = 1 shl 1
+        private const val KEY_POSITIONS_FLAG = 1 shl 2
+
+        /**
+         * [DebugFlags] instance with all flags disabled.
+         */
+        val None = DebugFlags(0)
+
+        /**
+         * [DebugFlags] instance with all flags enabled.
+         *
+         * Note that this includes any flags added in the future.
+         */
+        val All = DebugFlags(-1)
+    }
 }
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionMeasurer.kt b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionMeasurer.kt
index e768017..6929f33 100644
--- a/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionMeasurer.kt
+++ b/constraintlayout/constraintlayout-compose/src/androidMain/kotlin/androidx/constraintlayout/compose/MotionMeasurer.kt
@@ -175,7 +175,7 @@
             )
             // Build constraint set and apply it to the state.
             state.rootIncomingConstraints = constraints
-            state.isLtr = layoutDirection == LayoutDirection.Ltr
+            state.isRtl = layoutDirection == LayoutDirection.Rtl
 
             measureConstraintSet(
                 optimizationLevel, constraintSetStart, measurables, constraints
@@ -529,7 +529,7 @@
     ) {
         clearConstraintSets()
 
-        state.isLtr = layoutDirection == LayoutDirection.Ltr
+        state.isRtl = layoutDirection == LayoutDirection.Rtl
         start.applyTo(state, emptyList())
         start.applyTo(this.transition, Transition.START)
         state.apply(root)
diff --git a/constraintlayout/constraintlayout-compose/src/androidTest/kotlin/androidx/constraintlayout/compose/DebugFlagsTest.kt b/constraintlayout/constraintlayout-compose/src/androidTest/kotlin/androidx/constraintlayout/compose/DebugFlagsTest.kt
new file mode 100644
index 0000000..76d06f2
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/src/androidTest/kotlin/androidx/constraintlayout/compose/DebugFlagsTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.constraintlayout.compose
+
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+import org.junit.Test
+
+@OptIn(ExperimentalMotionApi::class)
+class DebugFlagsTest {
+    @Test
+    fun testFlags() {
+        assertEquals(
+            DebugFlags.None,
+            DebugFlags()
+        )
+        assertEquals(
+            DebugFlags.None,
+            DebugFlags(
+                showBounds = false,
+                showPaths = false,
+                showKeyPositions = false
+            )
+        )
+
+        // Not equals because All includes potential future flags
+        assertNotEquals(
+            DebugFlags.All,
+            DebugFlags(
+                showBounds = true,
+                showPaths = true,
+                showKeyPositions = true
+            )
+        )
+
+        var flags = DebugFlags.All
+        assertTrue(flags.showBounds)
+        assertTrue(flags.showPaths)
+        assertTrue(flags.showKeyPositions)
+
+        flags = DebugFlags.None
+        assertFalse(flags.showBounds)
+        assertFalse(flags.showPaths)
+        assertFalse(flags.showKeyPositions)
+
+        flags = DebugFlags(showBounds = true, showPaths = true, showKeyPositions = true)
+        assertTrue(flags.showBounds)
+        assertTrue(flags.showPaths)
+        assertTrue(flags.showKeyPositions)
+
+        flags = DebugFlags(showBounds = false, showPaths = false, showKeyPositions = false)
+        assertFalse(flags.showBounds)
+        assertFalse(flags.showPaths)
+        assertFalse(flags.showKeyPositions)
+
+        flags = DebugFlags(showBounds = true)
+        assertTrue(flags.showBounds)
+        assertFalse(flags.showPaths)
+        assertFalse(flags.showKeyPositions)
+
+        flags = DebugFlags(showPaths = true)
+        assertFalse(flags.showBounds)
+        assertTrue(flags.showPaths)
+        assertFalse(flags.showKeyPositions)
+
+        flags = DebugFlags(showKeyPositions = true)
+        assertFalse(flags.showBounds)
+        assertFalse(flags.showPaths)
+        assertTrue(flags.showKeyPositions)
+    }
+
+    @Test
+    fun testToString() {
+        assertEquals(
+            "DebugFlags(showBounds = true, showPaths = true, showKeyPositions = true)",
+            DebugFlags.All.toString()
+        )
+        assertEquals(
+            "DebugFlags(showBounds = false, showPaths = false, showKeyPositions = false)",
+            DebugFlags.None.toString()
+        )
+
+        assertEquals(
+            "DebugFlags(showBounds = false, showPaths = false, showKeyPositions = false)",
+            DebugFlags().toString()
+        )
+        assertEquals(
+            "DebugFlags(showBounds = true, showPaths = true, showKeyPositions = true)",
+            DebugFlags(showBounds = true, showPaths = true, showKeyPositions = true).toString()
+        )
+        assertEquals(
+            "DebugFlags(showBounds = true, showPaths = false, showKeyPositions = false)",
+            DebugFlags(showBounds = true, showPaths = false, showKeyPositions = false).toString()
+        )
+        assertEquals(
+            "DebugFlags(showBounds = false, showPaths = true, showKeyPositions = false)",
+            DebugFlags(showBounds = false, showPaths = true, showKeyPositions = false).toString()
+        )
+        assertEquals(
+            "DebugFlags(showBounds = false, showPaths = false, showKeyPositions = true)",
+            DebugFlags(showBounds = false, showPaths = false, showKeyPositions = true).toString()
+        )
+    }
+}
\ No newline at end of file
diff --git a/constraintlayout/constraintlayout-core/api/current.txt b/constraintlayout/constraintlayout-core/api/current.txt
index fffd4db..13b5edd 100644
--- a/constraintlayout/constraintlayout-core/api/current.txt
+++ b/constraintlayout/constraintlayout-core/api/current.txt
@@ -2267,14 +2267,16 @@
     method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain(java.lang.Object!...);
     method public androidx.constraintlayout.core.state.helpers.GuidelineReference! horizontalGuideline(Object!);
     method public boolean isBaselineNeeded(androidx.constraintlayout.core.widgets.ConstraintWidget!);
-    method public boolean isLtr();
+    method @Deprecated public boolean isLtr();
+    method public boolean isRtl();
     method public void map(Object!, Object!);
     method public void reset();
     method public boolean sameFixedHeight(int);
     method public boolean sameFixedWidth(int);
     method public void setDpToPixel(androidx.constraintlayout.core.state.CorePixelDp!);
     method public androidx.constraintlayout.core.state.State! setHeight(androidx.constraintlayout.core.state.Dimension!);
-    method public void setLtr(boolean);
+    method @Deprecated public void setLtr(boolean);
+    method public void setRtl(boolean);
     method public void setTag(String!, String!);
     method public androidx.constraintlayout.core.state.State! setWidth(androidx.constraintlayout.core.state.Dimension!);
     method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain();
@@ -2497,9 +2499,7 @@
     method public void addChainElement(String, float, float, float);
     method public androidx.constraintlayout.core.state.helpers.ChainReference bias(float);
     method public float getBias();
-    method protected float getPostGoneMargin(String);
     method protected float getPostMargin(String);
-    method protected float getPreGoneMargin(String);
     method protected float getPreMargin(String);
     method public androidx.constraintlayout.core.state.State.Chain getStyle();
     method protected float getWeight(String);
diff --git a/constraintlayout/constraintlayout-core/api/public_plus_experimental_current.txt b/constraintlayout/constraintlayout-core/api/public_plus_experimental_current.txt
index fffd4db..13b5edd 100644
--- a/constraintlayout/constraintlayout-core/api/public_plus_experimental_current.txt
+++ b/constraintlayout/constraintlayout-core/api/public_plus_experimental_current.txt
@@ -2267,14 +2267,16 @@
     method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain(java.lang.Object!...);
     method public androidx.constraintlayout.core.state.helpers.GuidelineReference! horizontalGuideline(Object!);
     method public boolean isBaselineNeeded(androidx.constraintlayout.core.widgets.ConstraintWidget!);
-    method public boolean isLtr();
+    method @Deprecated public boolean isLtr();
+    method public boolean isRtl();
     method public void map(Object!, Object!);
     method public void reset();
     method public boolean sameFixedHeight(int);
     method public boolean sameFixedWidth(int);
     method public void setDpToPixel(androidx.constraintlayout.core.state.CorePixelDp!);
     method public androidx.constraintlayout.core.state.State! setHeight(androidx.constraintlayout.core.state.Dimension!);
-    method public void setLtr(boolean);
+    method @Deprecated public void setLtr(boolean);
+    method public void setRtl(boolean);
     method public void setTag(String!, String!);
     method public androidx.constraintlayout.core.state.State! setWidth(androidx.constraintlayout.core.state.Dimension!);
     method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain();
@@ -2497,9 +2499,7 @@
     method public void addChainElement(String, float, float, float);
     method public androidx.constraintlayout.core.state.helpers.ChainReference bias(float);
     method public float getBias();
-    method protected float getPostGoneMargin(String);
     method protected float getPostMargin(String);
-    method protected float getPreGoneMargin(String);
     method protected float getPreMargin(String);
     method public androidx.constraintlayout.core.state.State.Chain getStyle();
     method protected float getWeight(String);
diff --git a/constraintlayout/constraintlayout-core/api/restricted_current.txt b/constraintlayout/constraintlayout-core/api/restricted_current.txt
index 8d0e51f..2ce45b86 100644
--- a/constraintlayout/constraintlayout-core/api/restricted_current.txt
+++ b/constraintlayout/constraintlayout-core/api/restricted_current.txt
@@ -2268,14 +2268,16 @@
     method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain(java.lang.Object!...);
     method public androidx.constraintlayout.core.state.helpers.GuidelineReference! horizontalGuideline(Object!);
     method public boolean isBaselineNeeded(androidx.constraintlayout.core.widgets.ConstraintWidget!);
-    method public boolean isLtr();
+    method @Deprecated public boolean isLtr();
+    method public boolean isRtl();
     method public void map(Object!, Object!);
     method public void reset();
     method public boolean sameFixedHeight(int);
     method public boolean sameFixedWidth(int);
     method public void setDpToPixel(androidx.constraintlayout.core.state.CorePixelDp!);
     method public androidx.constraintlayout.core.state.State! setHeight(androidx.constraintlayout.core.state.Dimension!);
-    method public void setLtr(boolean);
+    method @Deprecated public void setLtr(boolean);
+    method public void setRtl(boolean);
     method public void setTag(String!, String!);
     method public androidx.constraintlayout.core.state.State! setWidth(androidx.constraintlayout.core.state.Dimension!);
     method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain();
@@ -2500,9 +2502,7 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addChainElement(Object, float, float, float, float, float);
     method public androidx.constraintlayout.core.state.helpers.ChainReference bias(float);
     method public float getBias();
-    method protected float getPostGoneMargin(String);
     method protected float getPostMargin(String);
-    method protected float getPreGoneMargin(String);
     method protected float getPreMargin(String);
     method public androidx.constraintlayout.core.state.State.Chain getStyle();
     method protected float getWeight(String);
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 fcc3c51..5f97bd2 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
@@ -1361,9 +1361,9 @@
             state.verticalGuideline(guidelineId);
         }
 
-        // Ignore LTR for Horizontal guidelines, since `start` & `end` represent the distance
-        // from `top` and `bottom` respectively
-        boolean isLtr = state.isLtr() || orientation == ConstraintWidget.HORIZONTAL;
+        // Layout direction may be ignored for Horizontal guidelines (placed along the Y axis),
+        // since `start` & `end` represent the `top` and `bottom` distances respectively.
+        boolean isLtr = !state.isRtl() || orientation == ConstraintWidget.HORIZONTAL;
 
         GuidelineReference guidelineReference = (GuidelineReference) reference.getFacade();
 
@@ -1444,7 +1444,7 @@
             State state,
             String elementName, CLObject element
     ) throws CLParsingException {
-        boolean isLtr = state.isLtr();
+        boolean isLtr = !state.isRtl();
         BarrierReference reference = state.barrier(elementName, State.Direction.END);
         ArrayList<String> constraints = element.names();
         if (constraints == null) {
@@ -1646,7 +1646,7 @@
                 //  where the bias needs to be reversed in RTL, we probably want a better or more
                 //  intuitive way to do this
                 value = layoutVariables.get(element.get(attributeName));
-                if (!state.isLtr()) {
+                if (state.isRtl()) {
                     value = 1f - value;
                 }
                 reference.horizontalBias(value);
@@ -1814,7 +1814,7 @@
             ConstraintReference reference,
             String constraintName
     ) throws CLParsingException {
-        boolean isLtr = state.isLtr();
+        boolean isLtr = !state.isRtl();
         CLArray constraint = element.getArrayOrNull(constraintName);
         if (constraint != null && constraint.size() > 1) {
             // params: target, anchor
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 30ad1b8..a0f208d 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
@@ -205,19 +205,39 @@
 
     /**
      * Set whether the layout direction is left to right (Ltr).
+     *
+     * @deprecated For consistency, use {@link #setRtl(boolean)} instead.
      */
+    @Deprecated
     public void setLtr(boolean isLtr) {
         mIsLtr = isLtr;
     }
 
     /**
      * Returns true if layout direction is left to right. False for right to left.
+     *
+     * @deprecated For consistency, use {@link #isRtl()} instead.
      */
+    @Deprecated
     public boolean isLtr() {
         return mIsLtr;
     }
 
     /**
+     * Set whether the layout direction is right to left (Rtl).
+     */
+    public void setRtl(boolean isRtl) {
+        mIsLtr = !isRtl;
+    }
+
+    /**
+     * Returns true if layout direction is right to left. False for left to right.
+     */
+    public boolean isRtl() {
+        return !mIsLtr;
+    }
+
+    /**
      * Clear the state
      */
     public void reset() {
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 8527241..3565d70 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
@@ -38,7 +38,7 @@
     /**
      * Parse a JSON string of a Transition and insert it into the Transition object
      *
-     * @deprecated dpToPixel is unused now
+     * @deprecated dpToPixel is not necessary, use {@link #parse(CLObject, Transition)} instead.
      * @param json       Transition Object to parse.
      * @param transition Transition Object to write transition to
      */
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 47547f9..51269c7 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
@@ -172,14 +172,14 @@
         return 0;
     }
 
-    protected float getPostGoneMargin(@NonNull String id) {
+    float getPostGoneMargin(@NonNull String id) {
         if (mMapPostGoneMargin != null && mMapPostGoneMargin.containsKey(id)) {
             return mMapPostGoneMargin.get(id);
         }
         return 0;
     }
 
-    protected float getPreGoneMargin(@NonNull String id) {
+    float getPreGoneMargin(@NonNull String id) {
         if (mMapPreGoneMargin != null && mMapPreGoneMargin.containsKey(id)) {
             return mMapPreGoneMargin.get(id);
         }
diff --git a/core/core-ktx/api/current.txt b/core/core-ktx/api/current.txt
index 801b56b..d3bbf86 100644
--- a/core/core-ktx/api/current.txt
+++ b/core/core-ktx/api/current.txt
@@ -614,7 +614,7 @@
     method public static inline void setPadding(android.view.View, @Px int size);
     method public static inline void setVisible(android.view.View, boolean);
     method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
-    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParamsTyped(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
     method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
     method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
   }
diff --git a/core/core-ktx/api/public_plus_experimental_current.txt b/core/core-ktx/api/public_plus_experimental_current.txt
index 801b56b..d3bbf86 100644
--- a/core/core-ktx/api/public_plus_experimental_current.txt
+++ b/core/core-ktx/api/public_plus_experimental_current.txt
@@ -614,7 +614,7 @@
     method public static inline void setPadding(android.view.View, @Px int size);
     method public static inline void setVisible(android.view.View, boolean);
     method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
-    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParamsTyped(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
     method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
     method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
   }
diff --git a/core/core-ktx/api/restricted_current.txt b/core/core-ktx/api/restricted_current.txt
index 801b56b..d3bbf86 100644
--- a/core/core-ktx/api/restricted_current.txt
+++ b/core/core-ktx/api/restricted_current.txt
@@ -614,7 +614,7 @@
     method public static inline void setPadding(android.view.View, @Px int size);
     method public static inline void setVisible(android.view.View, boolean);
     method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
-    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParamsTyped(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
     method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
     method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
   }
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index e9aa6cc..448a233 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -1839,8 +1839,9 @@
     method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
     method @Deprecated @ChecksSdkIntAtLeast(api=31, codename="S") public static boolean isAtLeastS();
     method @Deprecated @ChecksSdkIntAtLeast(api=32, codename="Sv2") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastSv2();
-    method @ChecksSdkIntAtLeast(api=33, codename="Tiramisu") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastT();
-    method @ChecksSdkIntAtLeast(codename="UpsideDownCake") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastU();
+    method @Deprecated @ChecksSdkIntAtLeast(api=33, codename="Tiramisu") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastT();
+    method @ChecksSdkIntAtLeast(api=34, codename="UpsideDownCake") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastU();
+    method @ChecksSdkIntAtLeast(codename="VanillaIceCream") @androidx.core.os.BuildCompat.PrereleaseSdkCheck public static boolean isAtLeastV();
     field @ChecksSdkIntAtLeast(extension=android.os.ext.SdkExtensions.AD_SERVICES) public static final int AD_SERVICES_EXTENSION_INT;
     field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.R) public static final int R_EXTENSION_INT;
     field @ChecksSdkIntAtLeast(extension=android.os.Build.VERSION_CODES.S) public static final int S_EXTENSION_INT;
diff --git a/core/core/src/androidTest/java/androidx/core/app/ActivityCompatTest.java b/core/core/src/androidTest/java/androidx/core/app/ActivityCompatTest.java
index ce59b98..bded6af 100644
--- a/core/core/src/androidTest/java/androidx/core/app/ActivityCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/ActivityCompatTest.java
@@ -30,6 +30,7 @@
 
 import android.Manifest;
 import android.app.Activity;
+import android.os.Build;
 import android.support.v4.BaseInstrumentationTestCase;
 import android.view.View;
 
@@ -153,7 +154,7 @@
     @Test
     @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
     public void testShouldShowRequestPermissionRationaleForPostNotifications() throws Throwable {
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             // permission doesn't exist yet, so should return false
             assertFalse(ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
                     Manifest.permission.POST_NOTIFICATIONS));
diff --git a/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java b/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
index 3119729..faf225c 100644
--- a/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
@@ -23,7 +23,6 @@
 import android.os.Build;
 import android.support.v4.BaseInstrumentationTestCase;
 
-import androidx.core.os.BuildCompat;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
@@ -118,7 +117,7 @@
         String[] args = { specialArg };
         int actualApiVersion = Build.VERSION.SDK_INT;
 
-        if (BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT >= 33) {
             assertFalse(specialArg + " should be skipped on API " + actualApiVersion,
                     mComponentActivity.shouldDumpInternalState(args));
         } else {
diff --git a/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
index 5d34169..3ce039d 100644
--- a/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
@@ -32,6 +32,7 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
+import android.os.Build;
 import android.support.v4.testutils.TestUtils;
 import android.util.DisplayMetrics;
 
@@ -538,7 +539,7 @@
         ColorStateList csl2 = ResourcesCompat.getColorStateList(
                 mResources, R.color.color_state_list, theme);
 
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < 33) {
             // Validate the failure case that's being worked around.
             assertEquals(csl, csl2);
         } else {
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 efb9aa0..9a7b9f8 100644
--- a/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/BuildCompatTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -29,6 +30,7 @@
 /**
  * Tests for {@link BuildCompat}.
  */
+@SuppressWarnings("deprecation")
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class BuildCompatTest {
@@ -63,4 +65,15 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = 33)
+    @Test
+    public void isAtLeastT_byMinSdk() {
+        assertTrue(BuildCompat.isAtLeastT());
+    }
+
+    @SdkSuppress(minSdkVersion = 34)
+    @Test
+    public void isAtLeastU_byMinSdk() {
+        assertTrue(BuildCompat.isAtLeastU());
+    }
 }
diff --git a/core/core/src/main/java/androidx/core/app/ActivityCompat.java b/core/core/src/main/java/androidx/core/app/ActivityCompat.java
index 5ec885e..bc39a35 100644
--- a/core/core/src/main/java/androidx/core/app/ActivityCompat.java
+++ b/core/core/src/main/java/androidx/core/app/ActivityCompat.java
@@ -529,7 +529,7 @@
                         + Arrays.toString(permissions) + " must not contain null or empty values");
             }
 
-            if (!BuildCompat.isAtLeastT()) {
+            if (Build.VERSION.SDK_INT < 33) {
                 if (TextUtils.equals(permissions[i], Manifest.permission.POST_NOTIFICATIONS)) {
                     indicesOfPermissionsToRemove.add(i);
                 }
@@ -592,7 +592,7 @@
     @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
     public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
             @NonNull String permission) {
-        if (!BuildCompat.isAtLeastT()
+        if (Build.VERSION.SDK_INT < 33
                 && TextUtils.equals(Manifest.permission.POST_NOTIFICATIONS, permission)) {
             // notification permission doesn't exist before T
             return false;
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 17c5d24..8f7f1e3 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -8431,9 +8431,9 @@
     }
 
     /**
-     * <p>Helper class to add Android TV extensions to notifications. To create a notification
-     * with a TV extension:
-     *
+     * Helper class to add Android TV extensions to notifications.
+     * <p>
+     * To create a notification with a TV extension:
      * <ol>
      *  <li>Create an {@link NotificationCompat.Builder}, setting any desired properties.
      *  <li>Create a {@link TvExtender}.
@@ -8447,13 +8447,16 @@
      * Notification notification = new NotificationCompat.Builder(context)
      *         ...
      *         .extend(new TvExtender()
-     *                 .set*(...))
+     *                 .setChannelId("channel id"))
      *         .build();
+     * NotificationManagerCompat.from(mContext).notify(0, notification);
      * </pre>
      *
      * <p>TV extensions can be accessed on an existing notification by using the
      * {@code TvExtender(Notification)} constructor, and then using the {@code get} methods
      * to access values.
+     *
+     * <p>Note that prior to {@link Build.VERSION_CODES#O} this field has no effect.
      */
     public static final class TvExtender implements Extender {
         private static final String TAG = "TvExtender";
diff --git a/core/core/src/main/java/androidx/core/content/ContextCompat.java b/core/core/src/main/java/androidx/core/content/ContextCompat.java
index 2f27b65..cd4e613 100644
--- a/core/core/src/main/java/androidx/core/content/ContextCompat.java
+++ b/core/core/src/main/java/androidx/core/content/ContextCompat.java
@@ -591,7 +591,7 @@
     @OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class)
     public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
         ObjectsCompat.requireNonNull(permission, "permission must be non-null");
-        if (!BuildCompat.isAtLeastT()
+        if (Build.VERSION.SDK_INT < 33
                 && TextUtils.equals(android.Manifest.permission.POST_NOTIFICATIONS, permission)) {
             return NotificationManagerCompat.from(context).areNotificationsEnabled()
                     ? PackageManager.PERMISSION_GRANTED
diff --git a/core/core/src/main/java/androidx/core/os/BuildCompat.java b/core/core/src/main/java/androidx/core/os/BuildCompat.java
index 0af43bd..7bed9ce 100644
--- a/core/core/src/main/java/androidx/core/os/BuildCompat.java
+++ b/core/core/src/main/java/androidx/core/os/BuildCompat.java
@@ -195,7 +195,8 @@
     @Deprecated
     public static boolean isAtLeastSv2() {
         return VERSION.SDK_INT >= 32
-                || (VERSION.SDK_INT >= 31 && isAtLeastPreReleaseCodename("Sv2", VERSION.CODENAME));
+                || (VERSION.SDK_INT >= 31
+                && isAtLeastPreReleaseCodename("Sv2", VERSION.CODENAME));
     }
 
     /**
@@ -206,9 +207,13 @@
      * removed and all calls must be replaced with {@code Build.VERSION.SDK_INT >= 33}.
      *
      * @return {@code true} if Tiramisu APIs are available for use, {@code false} otherwise
+     * @deprecated Android Tiramisu is a finalized release and this method is no longer necessary.
+     *             It will be removed in a future release of this library. Instead, use
+     *             {@code Build.VERSION.SDK_INT >= 33}.
      */
     @PrereleaseSdkCheck
     @ChecksSdkIntAtLeast(api = 33, codename = "Tiramisu")
+    @Deprecated
     public static boolean isAtLeastT() {
         return VERSION.SDK_INT >= 33
                 || (VERSION.SDK_INT >= 32
@@ -216,19 +221,36 @@
     }
 
     /**
-     * Checks if the device is running on a pre-release version of Android U.
+     * Checks if the device is running on a pre-release version of Android UpsideDownCake or a
+     * release version of Android UpsideDownCake or newer.
      * <p>
-     * <strong>Note:</strong> When Android U is finalized for release, this method will be
-     * removed and all calls must be replaced with {@code Build.VERSION.SDK_INT >=
-     * Build.VERSION_CODES.U}.
+     * <strong>Note:</strong> When Android UpsideDownCake is finalized for release, this method
+     * will be removed and all calls must be replaced with {@code Build.VERSION.SDK_INT >= 34}.
      *
-     * @return {@code true} if U APIs are available for use, {@code false} otherwise
+     * @return {@code true} if UpsideDownCake APIs are available for use, {@code false} otherwise
      */
     @PrereleaseSdkCheck
-    @ChecksSdkIntAtLeast(codename = "UpsideDownCake")
+    @ChecksSdkIntAtLeast(api = 34, codename = "UpsideDownCake")
     public static boolean isAtLeastU() {
-        return VERSION.SDK_INT >= 33
-                && isAtLeastPreReleaseCodename("UpsideDownCake", VERSION.CODENAME);
+        return VERSION.SDK_INT >= 34
+                || (VERSION.SDK_INT >= 33
+                && isAtLeastPreReleaseCodename("UpsideDownCake", VERSION.CODENAME));
+    }
+
+    /**
+     * Checks if the device is running on a pre-release version of Android VanillaIceCream.
+     * <p>
+     * <strong>Note:</strong> When Android anillaIceCream is finalized for release, this method will
+     * be removed and all calls must be replaced with {@code Build.VERSION.SDK_INT >=
+     * Build.VERSION_CODES.VANILLA_ICE_CREAM}.
+     *
+     * @return {@code true} if VanillaIceCream APIs are available for use, {@code false} otherwise
+     */
+    @PrereleaseSdkCheck
+    @ChecksSdkIntAtLeast(codename = "VanillaIceCream")
+    public static boolean isAtLeastV() {
+        return VERSION.SDK_INT >= 34
+                && isAtLeastPreReleaseCodename("VanillaIceCream", VERSION.CODENAME);
     }
 
     /**
diff --git a/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml b/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
index 28e94cd..24737ae 100644
--- a/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
+++ b/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
@@ -27,6 +27,7 @@
         </service>
         <activity
             android:name="androidx.credentials.playservices.HiddenActivity"
+            android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
             android:exported="false"
             android:enabled="true"
             android:fitsSystemWindows="true"
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
index 1df0251..725d21b 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
@@ -44,6 +44,7 @@
 open class HiddenActivity : Activity() {
 
     private var resultReceiver: ResultReceiver? = null
+    private var mWaitingForActivityResult = false
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -56,6 +57,11 @@
             finish()
         }
 
+        restoreState(savedInstanceState)
+        if (mWaitingForActivityResult) {
+            return; // Past call still active
+        }
+
         when (type) {
             CredentialProviderBaseController.BEGIN_SIGN_IN_TAG -> {
                 handleBeginSignIn()
@@ -72,6 +78,12 @@
         }
     }
 
+    private fun restoreState(savedInstanceState: Bundle?) {
+        if (savedInstanceState != null) {
+            mWaitingForActivityResult = savedInstanceState.getBoolean(KEY_AWAITING_RESULT, false)
+        }
+    }
+
     private fun handleCreatePublicKeyCredential() {
         val fidoRegistrationRequest: PublicKeyCredentialCreationOptions? = intent
             .getParcelableExtra(CredentialProviderBaseController.REQUEST_TAG)
@@ -83,6 +95,7 @@
                 .getRegisterPendingIntent(fidoRegistrationRequest)
                 .addOnSuccessListener { result: PendingIntent ->
                     try {
+                        mWaitingForActivityResult = true
                         startIntentSenderForResult(
                             result.intentSender,
                             requestCode,
@@ -125,6 +138,11 @@
         finish()
     }
 
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult)
+        super.onSaveInstanceState(outState)
+    }
+
     private fun handleBeginSignIn() {
         val params: BeginSignInRequest? = intent.getParcelableExtra(
             CredentialProviderBaseController.REQUEST_TAG)
@@ -134,6 +152,7 @@
         params?.let {
             Identity.getSignInClient(this).beginSignIn(params).addOnSuccessListener {
                 try {
+                    mWaitingForActivityResult = true
                     startIntentSenderForResult(
                         it.pendingIntent.intentSender,
                         requestCode,
@@ -175,6 +194,7 @@
             Identity.getCredentialSavingClient(this).savePassword(params)
                 .addOnSuccessListener {
                     try {
+                        mWaitingForActivityResult = true
                         startIntentSenderForResult(
                             it.pendingIntent.intentSender,
                             requestCode,
@@ -186,7 +206,7 @@
                         )
                     } catch (e: IntentSender.SendIntentException) {
                         setupFailure(resultReceiver!!,
-                            GetCredentialUnknownException::class.java.name,
+                            CreateCredentialUnknownException::class.java.name,
                                 "During save password, found UI intent sender " +
                                     "failure: ${e.message}")
                     }
@@ -213,11 +233,13 @@
         bundle.putInt(CredentialProviderBaseController.ACTIVITY_REQUEST_CODE_TAG, requestCode)
         bundle.putParcelable(CredentialProviderBaseController.RESULT_DATA_TAG, data)
         resultReceiver?.send(resultCode, bundle)
+        mWaitingForActivityResult = false
         finish()
     }
 
     companion object {
         private const val DEFAULT_VALUE: Int = 1
         private val TAG: String = HiddenActivity::class.java.name
+        private const val KEY_AWAITING_RESULT = "androidx.credentials.playservices.AWAITING_RESULT"
     }
 }
\ No newline at end of file
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
index c6d6fcb..7e9365d 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
@@ -19,9 +19,11 @@
 import android.content.Intent
 import android.os.Parcel
 import android.os.ResultReceiver
+import androidx.credentials.exceptions.CreateCredentialCancellationException
 import androidx.credentials.exceptions.CreateCredentialException
 import androidx.credentials.exceptions.CreateCredentialInterruptedException
 import androidx.credentials.exceptions.CreateCredentialUnknownException
+import androidx.credentials.exceptions.GetCredentialCancellationException
 import androidx.credentials.exceptions.GetCredentialException
 import androidx.credentials.exceptions.GetCredentialInterruptedException
 import androidx.credentials.exceptions.GetCredentialUnknownException
@@ -86,6 +88,9 @@
         internal fun getCredentialExceptionTypeToException(typeName: String?, msg: String?):
             GetCredentialException {
             return when (typeName) {
+                GetCredentialCancellationException::class.java.name -> {
+                    GetCredentialCancellationException(msg)
+                }
                 GetCredentialInterruptedException::class.java.name -> {
                     GetCredentialInterruptedException(msg)
                 }
@@ -101,6 +106,9 @@
         internal fun createCredentialExceptionTypeToException(typeName: String?, msg: String?):
             CreateCredentialException {
             return when (typeName) {
+                CreateCredentialCancellationException::class.java.name -> {
+                    CreateCredentialCancellationException(msg)
+                }
                 CreateCredentialInterruptedException::class.java.name -> {
                     CreateCredentialInterruptedException(msg)
                 }
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
index 2e75b82..4278e5f 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderController.kt
@@ -155,9 +155,10 @@
         val errType = resultData.getString(EXCEPTION_TYPE_TAG)
         val errMsg = resultData.getString(EXCEPTION_MESSAGE_TAG)
         val exception = conversionFn(errType, errMsg)
-        cancelOrCallbackExceptionOrResult(cancellationSignal) {
+        cancelOrCallbackExceptionOrResult(cancellationSignal = cancellationSignal,
+            onResultOrException = {
             executor.execute { callback.onError(exception) }
-        }
+        })
         return true
     }
 
diff --git a/datastore/datastore-benchmark/build.gradle b/datastore/datastore-benchmark/build.gradle
new file mode 100644
index 0000000..97ed619
--- /dev/null
+++ b/datastore/datastore-benchmark/build.gradle
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("androidx.benchmark")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    androidTestImplementation(project(":datastore:datastore-core"))
+    androidTestImplementation(project(":internal-testutils-datastore"))
+    androidTestImplementation(libs.kotlinStdlib)
+    androidTestImplementation(projectOrArtifact(":benchmark:benchmark-junit4"))
+    androidTestImplementation(libs.junit)
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.kotlinCoroutinesTest)
+}
+
+android {
+    namespace "androidx.collection.benchmark"
+}
diff --git a/datastore/datastore-benchmark/src/androidTest/AndroidManifest.xml b/datastore/datastore-benchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..20b8acb
--- /dev/null
+++ b/datastore/datastore-benchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <application>
+        <!-- enable profiling by shell for non-intrusive profiling tools -->
+        <profileable android:shell="true"/>
+    </application>
+</manifest>
diff --git a/datastore/datastore-benchmark/src/androidTest/java/androidx/datastore/core/SingleProcessDatastoreTest.kt b/datastore/datastore-benchmark/src/androidTest/java/androidx/datastore/core/SingleProcessDatastoreTest.kt
new file mode 100644
index 0000000..f74d565
--- /dev/null
+++ b/datastore/datastore-benchmark/src/androidTest/java/androidx/datastore/core/SingleProcessDatastoreTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.core
+
+import androidx.benchmark.junit4.BenchmarkRule
+import androidx.benchmark.junit4.measureRepeated
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.MediumTest
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class SingleProcessDatastoreTest {
+    @get:Rule
+    val benchmark = BenchmarkRule()
+
+    @get:Rule
+    val tmp = TemporaryFolder()
+    private lateinit var testScope: TestScope
+    private lateinit var dataStoreScope: TestScope
+
+    @Before
+    fun setUp() {
+        testScope = TestScope(UnconfinedTestDispatcher())
+        dataStoreScope = TestScope(UnconfinedTestDispatcher())
+    }
+
+    @Test
+    @LargeTest
+    fun create() = testScope.runTest {
+        benchmark.measureRepeated {
+            val testFile = tmp.newFile()
+            val store = DataStoreFactory.create(
+                serializer = TestingSerializer(),
+                scope = dataStoreScope
+            ) { testFile }
+            runWithTimingDisabled {
+                Assert.assertNotNull(store)
+            }
+        }
+    }
+
+    @Test
+    @MediumTest
+    fun read() = testScope.runTest {
+        val scope = this
+        val testFile = tmp.newFile()
+        val store = DataStoreFactory.create(
+            serializer = TestingSerializer(),
+            scope = dataStoreScope
+        ) { testFile }
+        store.updateData { 1 }
+        benchmark.measureRepeated {
+            runBlocking(scope.coroutineContext) {
+                val data = store.data.first()
+                runWithTimingDisabled {
+                    val exp: Byte = 1
+                    Assert.assertEquals(exp, data)
+                }
+            }
+        }
+    }
+
+    @Test
+    @MediumTest
+    fun update() = testScope.runTest {
+        val scope = this
+        val testFile = tmp.newFile()
+        val store = DataStoreFactory.create(
+            serializer = TestingSerializer(),
+            scope = dataStoreScope
+        ) { testFile }
+        benchmark.measureRepeated {
+            runBlocking(scope.coroutineContext) {
+                store.updateData { 1 }
+                val data = store.data.first()
+                runWithTimingDisabled {
+                    val exp: Byte = 1
+                    Assert.assertEquals(exp, data)
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-core-okio/api/current.txt b/datastore/datastore-core-okio/api/current.txt
index bbcb949..08053b5 100644
--- a/datastore/datastore-core-okio/api/current.txt
+++ b/datastore/datastore-core-okio/api/current.txt
@@ -9,7 +9,7 @@
   }
 
   public final class OkioStorage<T> implements androidx.datastore.core.Storage<T> {
-    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, kotlin.jvm.functions.Function0<okio.Path> producePath);
+    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, optional kotlin.jvm.functions.Function2<? super okio.Path,? super okio.FileSystem,? extends androidx.datastore.core.InterProcessCoordinator> coordinatorProducer, kotlin.jvm.functions.Function0<okio.Path> producePath);
     method public androidx.datastore.core.StorageConnection<T> createConnection();
   }
 
diff --git a/datastore/datastore-core-okio/api/public_plus_experimental_current.txt b/datastore/datastore-core-okio/api/public_plus_experimental_current.txt
index bbcb949..08053b5 100644
--- a/datastore/datastore-core-okio/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-core-okio/api/public_plus_experimental_current.txt
@@ -9,7 +9,7 @@
   }
 
   public final class OkioStorage<T> implements androidx.datastore.core.Storage<T> {
-    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, kotlin.jvm.functions.Function0<okio.Path> producePath);
+    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, optional kotlin.jvm.functions.Function2<? super okio.Path,? super okio.FileSystem,? extends androidx.datastore.core.InterProcessCoordinator> coordinatorProducer, kotlin.jvm.functions.Function0<okio.Path> producePath);
     method public androidx.datastore.core.StorageConnection<T> createConnection();
   }
 
diff --git a/datastore/datastore-core-okio/api/res-current.txt b/datastore/datastore-core-okio/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/datastore/datastore-core-okio/api/res-current.txt
diff --git a/datastore/datastore-core-okio/api/restricted_current.txt b/datastore/datastore-core-okio/api/restricted_current.txt
index bbcb949..08053b5 100644
--- a/datastore/datastore-core-okio/api/restricted_current.txt
+++ b/datastore/datastore-core-okio/api/restricted_current.txt
@@ -9,7 +9,7 @@
   }
 
   public final class OkioStorage<T> implements androidx.datastore.core.Storage<T> {
-    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, kotlin.jvm.functions.Function0<okio.Path> producePath);
+    ctor public OkioStorage(okio.FileSystem fileSystem, androidx.datastore.core.okio.OkioSerializer<T> serializer, optional kotlin.jvm.functions.Function2<? super okio.Path,? super okio.FileSystem,? extends androidx.datastore.core.InterProcessCoordinator> coordinatorProducer, kotlin.jvm.functions.Function0<okio.Path> producePath);
     method public androidx.datastore.core.StorageConnection<T> createConnection();
   }
 
diff --git a/datastore/datastore-core-okio/build.gradle b/datastore/datastore-core-okio/build.gradle
index 9d4aa01..d1c5ba1 100644
--- a/datastore/datastore-core-okio/build.gradle
+++ b/datastore/datastore-core-okio/build.gradle
@@ -27,9 +27,7 @@
 def enableNative = KmpPlatformsKt.enableNative(project)
 
 androidXMultiplatform {
-    jvm() {
-        withJava()
-    }
+    jvm()
     mac()
     linux()
     ios()
diff --git a/datastore/datastore-core-okio/src/commonMain/kotlin/androidx/datastore/core/okio/OkioStorage.kt b/datastore/datastore-core-okio/src/commonMain/kotlin/androidx/datastore/core/okio/OkioStorage.kt
index e896d97..e2ff9fb 100644
--- a/datastore/datastore-core-okio/src/commonMain/kotlin/androidx/datastore/core/okio/OkioStorage.kt
+++ b/datastore/datastore-core-okio/src/commonMain/kotlin/androidx/datastore/core/okio/OkioStorage.kt
@@ -16,6 +16,7 @@
 
 package androidx.datastore.core.okio
 
+import androidx.datastore.core.InterProcessCoordinator
 import androidx.datastore.core.ReadScope
 import androidx.datastore.core.Storage
 import androidx.datastore.core.StorageConnection
@@ -36,10 +37,20 @@
 
 /**
  * OKIO implementation of the Storage interface, providing cross platform IO using the OKIO library.
+ *
+ * @param fileSystem The file system to perform IO operations on.
+ * @param serializer The serializer for `T`.
+ * @param coordinatorProducer The producer to provide [InterProcessCoordinator] that coordinates IO
+ * operations across processes if needed. By default it provides single process coordinator, which
+ * doesn't support cross process use cases.
+ * @param producePath The file producer that returns the file path that will be read and written.
  */
 public class OkioStorage<T>(
     private val fileSystem: FileSystem,
     private val serializer: OkioSerializer<T>,
+    private val coordinatorProducer: (Path, FileSystem) -> InterProcessCoordinator = { _, _ ->
+        createSingleProcessCoordinator()
+    },
     private val producePath: () -> Path
 ) : Storage<T> {
     private val canonicalPath by lazy {
@@ -63,7 +74,12 @@
                 activeFiles.add(path)
             }
         }
-        return OkioStorageConnection(fileSystem, canonicalPath, serializer) {
+        return OkioStorageConnection(
+            fileSystem,
+            canonicalPath,
+            serializer,
+            coordinatorProducer(canonicalPath, fileSystem)
+        ) {
             synchronized(activeFilesLock) {
                 activeFiles.remove(canonicalPath.toString())
             }
@@ -74,6 +90,7 @@
         internal val activeFiles = mutableSetOf<String>()
 
         class Sync : SynchronizedObject()
+
         internal val activeFilesLock = Sync()
     }
 }
@@ -82,13 +99,14 @@
     private val fileSystem: FileSystem,
     private val path: Path,
     private val serializer: OkioSerializer<T>,
+    override val coordinator: InterProcessCoordinator,
     private val onClose: () -> Unit
 ) : StorageConnection<T> {
 
     private val closed = AtomicBoolean(false)
+
     // TODO:(b/233402915) support multiple readers
     private val transactionMutex = Mutex()
-    override val coordinator = createSingleProcessCoordinator()
 
     override suspend fun <R> readScope(
         block: suspend ReadScope<T>.(locked: Boolean) -> R
@@ -178,6 +196,7 @@
     override fun close() {
         closed = true
     }
+
     protected fun checkClose() {
         check(!closed) { "This scope has already been closed." }
     }
diff --git a/datastore/datastore-core-okio/src/commonTest/kotlin/androidx/datastore/core/okio/OkioStorageTest.kt b/datastore/datastore-core-okio/src/commonTest/kotlin/androidx/datastore/core/okio/OkioStorageTest.kt
index 3df190d..f2b88b1 100644
--- a/datastore/datastore-core-okio/src/commonTest/kotlin/androidx/datastore/core/okio/OkioStorageTest.kt
+++ b/datastore/datastore-core-okio/src/commonTest/kotlin/androidx/datastore/core/okio/OkioStorageTest.kt
@@ -28,15 +28,15 @@
 import androidx.datastore.TestingSerializerConfig
 import androidx.kruth.assertThat
 import androidx.kruth.assertThrows
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlin.test.Test
 import kotlin.test.BeforeTest
 import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.async
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.yield
 import okio.FileSystem
 import okio.IOException
@@ -316,7 +316,7 @@
             }
             FileSystem.SYSTEM_TEMPORARY_DIRECTORY / "new-temp-file.tmp"
         }
-        val storage = OkioStorage(fileSystem, testingSerializer, fileProducer)
+        val storage = OkioStorage(fileSystem, testingSerializer, producePath = fileProducer)
 
         assertThrows<IOException> { storage.createConnection().use {
             it.readData()
diff --git a/datastore/datastore-core/src/androidAndroidTest/AndroidManifest.xml b/datastore/datastore-core/src/androidAndroidTest/AndroidManifest.xml
index 1fd5182..791dfd1 100644
--- a/datastore/datastore-core/src/androidAndroidTest/AndroidManifest.xml
+++ b/datastore/datastore-core/src/androidAndroidTest/AndroidManifest.xml
@@ -18,45 +18,85 @@
 
     <application>
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$SimpleUpdateService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$SimpleUpdateFileService"
             android:enabled="true"
             android:exported="false"
-            android:process=":SimpleUpdateService" />
+            android:process=":SimpleUpdateFileService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateWriterService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$SimpleUpdateOkioService"
             android:enabled="true"
             android:exported="false"
-            android:process=":ConcurrentReadUpdateWriterService" />
+            android:process=":SimpleUpdateOkioService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateReaderService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateWriterFileService"
             android:enabled="true"
             android:exported="false"
-            android:process=":ConcurrentReadUpdateReaderService" />
+            android:process=":ConcurrentReadUpdateWriterFileService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateWriterOkioService"
             android:enabled="true"
             android:exported="false"
-            android:process=":InterleavedUpdateDataService" />
+            android:process=":ConcurrentReadUpdateWriterOkioService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataWithReadService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateReaderFileService"
             android:enabled="true"
             android:exported="false"
-            android:process=":InterleavedUpdateDataWithReadService" />
+            android:process=":ConcurrentReadUpdateReaderFileService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$FailedUpdateDataService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$ConcurrentReadUpdateReaderOkioService"
             android:enabled="true"
             android:exported="false"
-            android:process=":FailedUpdateDataService" />
+            android:process=":ConcurrentReadUpdateReaderOkioService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$CancelledUpdateDataService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataFileService"
             android:enabled="true"
             android:exported="false"
-            android:process=":CancelledUpdateDataService" />
+            android:process=":InterleavedUpdateDataFileService" />
         <service
-            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedHandlerUpdateDataService"
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataOkioService"
             android:enabled="true"
             android:exported="false"
-            android:process=":InterleavedHandlerUpdateDataService" />
+            android:process=":InterleavedUpdateDataOkioService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataWithReadFileService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":InterleavedUpdateDataWithReadFileService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedUpdateDataWithReadOkioService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":InterleavedUpdateDataWithReadOkioService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$FailedUpdateDataFileService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":FailedUpdateDataFileService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$FailedUpdateDataOkioService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":FailedUpdateDataOkioService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$CancelledUpdateDataFileService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":CancelledUpdateDataFileService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$CancelledUpdateDataOkioService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":CancelledUpdateDataOkioService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedHandlerUpdateDataFileService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":InterleavedHandlerUpdateDataFileService" />
+        <service
+            android:name="androidx.datastore.core.MultiProcessDataStoreMultiProcessTest$InterleavedHandlerUpdateDataOkioService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":InterleavedHandlerUpdateDataOkioService" />
     </application>
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/DirectTestService.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/DirectTestService.kt
index 88d20b0..1dbe386 100644
--- a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/DirectTestService.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/DirectTestService.kt
@@ -74,7 +74,7 @@
     private lateinit var testFailure: Throwable
 
     // It should be setup in `beforeTest`
-    internal lateinit var store: DataStoreImpl<FooProto>
+    internal lateinit var store: DataStore<FooProto>
 
     override fun onBind(intent: Intent): IBinder {
         return messenger.getBinder()
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreMultiProcessTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreMultiProcessTest.kt
index 13bd3d7..27d5641 100644
--- a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreMultiProcessTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreMultiProcessTest.kt
@@ -20,6 +20,8 @@
 import android.os.Bundle
 import androidx.datastore.core.handlers.NoOpCorruptionHandler
 import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
+import androidx.datastore.core.okio.OkioSerializer
+import androidx.datastore.core.okio.OkioStorage
 import androidx.test.core.app.ApplicationProvider
 import androidx.testing.TestMessageProto.FooProto
 import com.google.common.truth.Truth.assertThat
@@ -42,6 +44,8 @@
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
+import okio.FileSystem
+import okio.Path.Companion.toPath
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -50,10 +54,17 @@
 import org.junit.runners.JUnit4
 
 private const val PATH_BUNDLE_KEY: String = "path"
+private const val STORAGE_BUNDLE_KEY: String = "storage"
+private const val STORAGE_FILE: String = "FILE"
+private const val STORAGE_OKIO: String = "OKIO"
 private val PROTO_SERIALIZER: Serializer<FooProto> = ProtoSerializer<FooProto>(
     FooProto.getDefaultInstance(),
     ExtensionRegistryLite.getEmptyRegistry()
 )
+private val PROTO_OKIO_SERIALIZER: OkioSerializer<FooProto> = ProtoOkioSerializer<FooProto>(
+    FooProto.getDefaultInstance(),
+    ExtensionRegistryLite.getEmptyRegistry()
+)
 private const val TEST_TEXT: String = "abc"
 internal val WRITE_TEXT: (FooProto) -> FooProto = { f: FooProto ->
     f.toBuilder().setText(TEST_TEXT).build()
@@ -62,7 +73,7 @@
     f.toBuilder().setBoolean(true).build()
 }
 private val INCREMENT_INTEGER: (FooProto) -> FooProto = { f: FooProto ->
-    f.toBuilder().setInteger(f.getInteger() + 1).build()
+    f.toBuilder().setInteger(f.integer + 1).build()
 }
 
 private val DEFAULT_FOO: FooProto = FooProto.getDefaultInstance()
@@ -71,25 +82,43 @@
 private val FOO_WITH_TEXT_AND_BOOLEAN: FooProto =
     FooProto.newBuilder().setText(TEST_TEXT).setBoolean(true).build()
 
+private val FILESYSTEM = FileSystem.SYSTEM
+
 @ExperimentalCoroutinesApi
 private fun createDataStore(
     bundle: Bundle,
     scope: TestScope,
-    corruptionHandler: CorruptionHandler<FooProto> = NoOpCorruptionHandler<FooProto>()
-): DataStoreImpl<FooProto> {
+    corruptionHandler: CorruptionHandler<FooProto> = NoOpCorruptionHandler<FooProto>(),
+    context: CoroutineContext = UnconfinedTestDispatcher()
+): DataStore<FooProto> {
     val file = File(bundle.getString(PATH_BUNDLE_KEY)!!)
     val produceFile = { file }
-    return DataStoreImpl<FooProto>(
-        storage = FileStorage(
+    val variant = StorageVariant.valueOf(bundle.getString(STORAGE_BUNDLE_KEY)!!)
+    val storage = if (variant == StorageVariant.FILE) {
+        FileStorage(
             PROTO_SERIALIZER,
-            { MultiProcessCoordinator(UnconfinedTestDispatcher(), it) },
+            { MultiProcessCoordinator(context, it) },
             produceFile
-        ),
+        )
+    } else {
+        OkioStorage(
+            FILESYSTEM,
+            PROTO_OKIO_SERIALIZER,
+            { _, _ -> MultiProcessCoordinator(context, file) },
+            { file.absolutePath.toPath() }
+        )
+    }
+    return DataStoreImpl(
+        storage = storage,
         scope = scope,
         corruptionHandler = corruptionHandler
     )
 }
 
+internal enum class StorageVariant(val storage: String) {
+    FILE(STORAGE_FILE), OKIO(STORAGE_OKIO)
+}
+
 @OptIn(DelicateCoroutinesApi::class)
 @ExperimentalCoroutinesApi
 @RunWith(JUnit4::class)
@@ -101,34 +130,15 @@
     private lateinit var dataStoreContext: CoroutineContext
     private lateinit var dataStoreScope: TestScope
 
-    private val protoSerializer: Serializer<FooProto> = ProtoSerializer<FooProto>(
-        FooProto.getDefaultInstance(),
-        ExtensionRegistryLite.getEmptyRegistry()
-    )
     private val mainContext: Context = ApplicationProvider.getApplicationContext()
 
-    private fun createDataStoreBundle(path: String): Bundle {
+    private fun createDataStoreBundle(path: String, variant: StorageVariant): Bundle {
         val data = Bundle()
         data.putString(PATH_BUNDLE_KEY, path)
+        data.putString(STORAGE_BUNDLE_KEY, variant.storage)
         return data
     }
 
-    private fun createDataStore(
-        bundle: Bundle,
-        scope: TestScope
-    ): DataStoreImpl<FooProto> {
-        val file = File(bundle.getString(PATH_BUNDLE_KEY)!!)
-        val produceFile = { file }
-        return DataStoreImpl<FooProto>(
-            storage = FileStorage(
-                protoSerializer,
-                { MultiProcessCoordinator(dataStoreContext, it) },
-                produceFile
-            ),
-            scope = scope
-        )
-    }
-
     @Before
     fun setUp() {
         testFile = tempFolder.newFile()
@@ -137,22 +147,32 @@
     }
 
     @Test
-    fun testSimpleUpdateData() = runTest {
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope)
-        val connection: BlockingServiceConnection =
-            setUpService(mainContext, SimpleUpdateService::class.java, testData)
+    fun testSimpleUpdateData_file() = testSimpleUpdateData_runner(StorageVariant.FILE)
 
-        assertThat(dataStore.data.first()).isEqualTo(DEFAULT_FOO)
+    @Test
+    fun testSimpleUpdateData_okio() = testSimpleUpdateData_runner(StorageVariant.OKIO)
 
-        // Other proc commits TEST_TEXT update
-        signalService(connection)
+    private fun testSimpleUpdateData_runner(variant: StorageVariant) =
+        runTest(dispatchTimeoutMs = 10000) {
+            val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+            val dataStore: DataStore<FooProto> =
+                createDataStore(testData, dataStoreScope, context = dataStoreContext)
+            val serviceClasses = mapOf(
+                StorageVariant.FILE to SimpleUpdateFileService::class,
+                StorageVariant.OKIO to SimpleUpdateOkioService::class
+            )
+            val connection: BlockingServiceConnection =
+                setUpService(mainContext, serviceClasses[variant]!!.java, testData)
 
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
-    }
+            assertThat(dataStore.data.first()).isEqualTo(DEFAULT_FOO)
 
-    class SimpleUpdateService(
+            // Other proc commits TEST_TEXT update
+            signalService(connection)
+
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
+        }
+
+    open class SimpleUpdateFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -166,37 +186,53 @@
         }
     }
 
+    class SimpleUpdateOkioService : SimpleUpdateFileService()
+
     @Test
-    fun testConcurrentReadUpdate() = runTest {
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope)
-        val writerConnection: BlockingServiceConnection =
-            setUpService(mainContext, ConcurrentReadUpdateWriterService::class.java, testData)
+    fun testConcurrentReadUpdate_file() = testConcurrentReadUpdate_runner(StorageVariant.FILE)
 
-        // Start with TEST_TEXT
-        dataStore.updateData { f: FooProto -> WRITE_TEXT(f) }
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
+    @Test
+    fun testConcurrentReadUpdate_okio() = testConcurrentReadUpdate_runner(StorageVariant.OKIO)
 
-        // Writer process starts (but does not yet commit) "true"
-        signalService(writerConnection)
+    private fun testConcurrentReadUpdate_runner(variant: StorageVariant) =
+        runTest(dispatchTimeoutMs = 10000) {
+            val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+            val dataStore: DataStore<FooProto> =
+                createDataStore(testData, dataStoreScope, context = dataStoreContext)
+            val writerServiceClasses = mapOf(
+                StorageVariant.FILE to ConcurrentReadUpdateWriterFileService::class,
+                StorageVariant.OKIO to ConcurrentReadUpdateWriterOkioService::class
+            )
+            val writerConnection: BlockingServiceConnection =
+                setUpService(mainContext, writerServiceClasses[variant]!!.java, testData)
 
-        // We can continue reading datastore while the writer process is mid-write
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
+            // Start with TEST_TEXT
+            dataStore.updateData { f: FooProto -> WRITE_TEXT(f) }
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
 
-        // New processes that start in the meantime can also read
-        val readerConnection: BlockingServiceConnection =
-            setUpService(mainContext, ConcurrentReadUpdateReaderService::class.java, testData)
-        signalService(readerConnection)
+            // Writer process starts (but does not yet commit) "true"
+            signalService(writerConnection)
 
-        // The other process finishes writing "true"; we (and other readers) should pick up the new data
-        signalService(writerConnection)
+            // We can continue reading datastore while the writer process is mid-write
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
 
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
-        signalService(readerConnection)
-    }
+            val readerServiceClasses = mapOf(
+                StorageVariant.FILE to ConcurrentReadUpdateReaderFileService::class,
+                StorageVariant.OKIO to ConcurrentReadUpdateReaderOkioService::class
+            )
+            // New processes that start in the meantime can also read
+            val readerConnection: BlockingServiceConnection =
+                setUpService(mainContext, readerServiceClasses[variant]!!.java, testData)
+            signalService(readerConnection)
 
-    class ConcurrentReadUpdateWriterService(
+            // The other process finishes writing "true"; we (and other readers) should pick up the new data
+            signalService(writerConnection)
+
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
+            signalService(readerConnection)
+        }
+
+    open class ConcurrentReadUpdateWriterFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -211,7 +247,9 @@
         }
     }
 
-    class ConcurrentReadUpdateReaderService(
+    class ConcurrentReadUpdateWriterOkioService : ConcurrentReadUpdateWriterFileService()
+
+    open class ConcurrentReadUpdateReaderFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -225,40 +263,52 @@
         }
     }
 
+    class ConcurrentReadUpdateReaderOkioService : ConcurrentReadUpdateReaderFileService()
+
     @Test
-    fun testInterleavedUpdateData() = runTest(UnconfinedTestDispatcher()) {
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope)
-        val connection: BlockingServiceConnection =
-            setUpService(mainContext, InterleavedUpdateDataService::class.java, testData)
+    fun testInterleavedUpdateData_file() = testInterleavedUpdateData_runner(StorageVariant.FILE)
 
-        // Other proc starts TEST_TEXT update, then waits for signal
-        signalService(connection)
+    @Test
+    fun testInterleavedUpdateData_okio() = testInterleavedUpdateData_runner(StorageVariant.OKIO)
 
-        // We start "true" update, then wait for condition
-        val condition = CompletableDeferred<Unit>()
-        val write = async(newSingleThreadContext("blockedWriter")) {
-            dataStore.updateData {
-                condition.await()
-                WRITE_BOOLEAN(it)
-            }
-        }
+    private fun testInterleavedUpdateData_runner(variant: StorageVariant) =
+        runTest(UnconfinedTestDispatcher(), dispatchTimeoutMs = 10000) {
+            val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+            val dataStore: DataStore<FooProto> =
+                createDataStore(testData, dataStoreScope, context = dataStoreContext)
+            val serviceClasses = mapOf(
+                StorageVariant.FILE to InterleavedUpdateDataFileService::class,
+                StorageVariant.OKIO to InterleavedUpdateDataOkioService::class
+            )
+            val connection: BlockingServiceConnection =
+                setUpService(mainContext, serviceClasses[variant]!!.java, testData)
 
-        // Allow the other proc's update to run to completion, then allow ours to run to completion
-        val unblockOurUpdate = async {
-            delay(100)
+            // Other proc starts TEST_TEXT update, then waits for signal
             signalService(connection)
-            condition.complete(Unit)
+
+            // We start "true" update, then wait for condition
+            val condition = CompletableDeferred<Unit>()
+            val write = async(newSingleThreadContext("blockedWriter")) {
+                dataStore.updateData {
+                    condition.await()
+                    WRITE_BOOLEAN(it)
+                }
+            }
+
+            // Allow the other proc's update to run to completion, then allow ours to run to completion
+            val unblockOurUpdate = async {
+                delay(100)
+                signalService(connection)
+                condition.complete(Unit)
+            }
+
+            unblockOurUpdate.await()
+            write.await()
+
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
         }
 
-        unblockOurUpdate.await()
-        write.await()
-
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
-    }
-
-    class InterleavedUpdateDataService(
+    open class InterleavedUpdateDataFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -273,55 +323,75 @@
         }
     }
 
+    class InterleavedUpdateDataOkioService : InterleavedUpdateDataFileService()
+
     @Test
-    fun testInterleavedUpdateDataWithLocalRead() = runTest(UnconfinedTestDispatcher()) {
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope)
-        val connection: BlockingServiceConnection =
-            setUpService(mainContext, InterleavedUpdateDataWithReadService::class.java, testData)
+    fun testInterleavedUpdateDataWithLocalRead_file() =
+        testInterleavedUpdateDataWithLocalRead_runner(StorageVariant.FILE)
 
-        // Invalidate any local cache
-        assertThat(dataStore.data.first()).isEqualTo(DEFAULT_FOO)
-        signalService(connection)
+    @Test
+    fun testInterleavedUpdateDataWithLocalRead_okio() =
+        testInterleavedUpdateDataWithLocalRead_runner(StorageVariant.OKIO)
 
-        // Queue and start local write
-        val writeStarted = CompletableDeferred<Unit>()
-        val finishWrite = CompletableDeferred<Unit>()
+    private fun testInterleavedUpdateDataWithLocalRead_runner(variant: StorageVariant) =
+        runTest(UnconfinedTestDispatcher(), dispatchTimeoutMs = 10000) {
+            val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+            val dataStore: DataStore<FooProto> =
+                createDataStore(testData, dataStoreScope, context = dataStoreContext)
+            val serviceClasses = mapOf(
+                StorageVariant.FILE to InterleavedUpdateDataWithReadFileService::class,
+                StorageVariant.OKIO to InterleavedUpdateDataWithReadOkioService::class
+            )
+            val connection: BlockingServiceConnection =
+                setUpService(
+                    mainContext,
+                    serviceClasses[variant]!!.java,
+                    testData
+                )
 
-        val write = async {
-            dataStore.updateData {
-                writeStarted.complete(Unit)
-                finishWrite.await()
-                FOO_WITH_TEXT
-            }
-        }
-        writeStarted.await()
-
-        // Queue remote write
-        signalService(connection)
-
-        // Local uncached read; this should see data initially written remotely.
-        assertThat(dataStore.data.first()).isEqualTo(FooProto.newBuilder().setInteger(1).build())
-
-        // Unblock writes; the local write is delayed to ensure the remote write remains blocked.
-        val remoteWrite = async(newSingleThreadContext("blockedWriter")) {
+            // Invalidate any local cache
+            assertThat(dataStore.data.first()).isEqualTo(DEFAULT_FOO)
             signalService(connection)
+
+            // Queue and start local write
+            val writeStarted = CompletableDeferred<Unit>()
+            val finishWrite = CompletableDeferred<Unit>()
+
+            val write = async {
+                dataStore.updateData {
+                    writeStarted.complete(Unit)
+                    finishWrite.await()
+                    FOO_WITH_TEXT
+                }
+            }
+            writeStarted.await()
+
+            // Queue remote write
+            signalService(connection)
+
+            // Local uncached read; this should see data initially written remotely.
+            assertThat(dataStore.data.first()).isEqualTo(
+                FooProto.newBuilder().setInteger(1).build()
+            )
+
+            // Unblock writes; the local write is delayed to ensure the remote write remains blocked.
+            val remoteWrite = async(newSingleThreadContext("blockedWriter")) {
+                signalService(connection)
+            }
+
+            val localWrite = async(newSingleThreadContext("unblockLocalWrite")) {
+                delay(500)
+                finishWrite.complete(Unit)
+                write.await()
+            }
+
+            localWrite.await()
+            remoteWrite.await()
+
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
         }
 
-        val localWrite = async(newSingleThreadContext("unblockLocalWrite")) {
-            delay(500)
-            finishWrite.complete(Unit)
-            write.await()
-        }
-
-        localWrite.await()
-        remoteWrite.await()
-
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT_AND_BOOLEAN)
-    }
-
-    class InterleavedUpdateDataWithReadService(
+    open class InterleavedUpdateDataWithReadFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -345,13 +415,28 @@
         }
     }
 
+    class InterleavedUpdateDataWithReadOkioService : InterleavedUpdateDataWithReadFileService()
+
     @Test
-    fun testUpdateDataExceptionUnblocksOtherProcessFromWriting() = runTest {
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope)
+    fun testUpdateDataExceptionUnblocksOtherProcessFromWriting_file() =
+        testUpdateDataExceptionUnblocksOtherProcessFromWriting_runner(StorageVariant.FILE)
+
+    @Test
+    fun testUpdateDataExceptionUnblocksOtherProcessFromWriting_okio() =
+        testUpdateDataExceptionUnblocksOtherProcessFromWriting_runner(StorageVariant.OKIO)
+
+    private fun testUpdateDataExceptionUnblocksOtherProcessFromWriting_runner(
+        variant: StorageVariant
+    ) = runTest(dispatchTimeoutMs = 10000) {
+        val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+        val dataStore: DataStore<FooProto> =
+            createDataStore(testData, dataStoreScope, context = dataStoreContext)
+        val serviceClasses = mapOf(
+            StorageVariant.FILE to FailedUpdateDataFileService::class,
+            StorageVariant.OKIO to FailedUpdateDataOkioService::class
+        )
         val connection: BlockingServiceConnection =
-            setUpService(mainContext, FailedUpdateDataService::class.java, testData)
+            setUpService(mainContext, serviceClasses[variant]!!.java, testData)
 
         val blockWrite = CompletableDeferred<Unit>()
         val waitForWrite = CompletableDeferred<Unit>()
@@ -381,7 +466,7 @@
         assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
     }
 
-    class FailedUpdateDataService(
+    open class FailedUpdateDataFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -395,16 +480,29 @@
         }
     }
 
+    class FailedUpdateDataOkioService : FailedUpdateDataFileService()
+
     @Test
-    fun testUpdateDataCancellationUnblocksOtherProcessFromWriting() = runTest(
-        UnconfinedTestDispatcher()
-    ) {
+    fun testUpdateDataCancellationUnblocksOtherProcessFromWriting_file() =
+        testUpdateDataCancellationUnblocksOtherProcessFromWriting_runner(StorageVariant.FILE)
+
+    @Test
+    fun testUpdateDataCancellationUnblocksOtherProcessFromWriting_okio() =
+        testUpdateDataCancellationUnblocksOtherProcessFromWriting_runner(StorageVariant.OKIO)
+
+    private fun testUpdateDataCancellationUnblocksOtherProcessFromWriting_runner(
+        variant: StorageVariant
+    ) = runTest(UnconfinedTestDispatcher(), dispatchTimeoutMs = 10000) {
         val localScope = TestScope(UnconfinedTestDispatcher() + Job())
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, localScope)
+        val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+        val dataStore: DataStore<FooProto> =
+            createDataStore(testData, localScope, context = dataStoreContext)
+        val serviceClasses = mapOf(
+            StorageVariant.FILE to CancelledUpdateDataFileService::class,
+            StorageVariant.OKIO to CancelledUpdateDataOkioService::class
+        )
         val connection: BlockingServiceConnection =
-            setUpService(mainContext, CancelledUpdateDataService::class.java, testData)
+            setUpService(mainContext, serviceClasses[variant]!!.java, testData)
 
         val blockWrite = CompletableDeferred<Unit>()
 
@@ -433,7 +531,7 @@
     // A duplicate from CancelledUpdateDataService to make sure Android framework would create a
     // new process for this test. Otherwise the test would hang infinitely because the tests bind
     // to an existing service created by the previous test.
-    class CancelledUpdateDataService(
+    open class CancelledUpdateDataFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -447,35 +545,47 @@
         }
     }
 
+    class CancelledUpdateDataOkioService : CancelledUpdateDataFileService()
+
     @Test
-    fun testReadUpdateCorrupt() = runTest {
-        FileOutputStream(testFile).use {
-            OutputStreamWriter(it).write("garbage")
-        }
-        val testData: Bundle = createDataStoreBundle(testFile.absolutePath)
-        val connection: BlockingServiceConnection =
-            setUpService(mainContext, InterleavedHandlerUpdateDataService::class.java, testData)
-        val corruptionHandler = ReplaceFileCorruptionHandler<FooProto> {
+    fun testReadUpdateCorrupt_file() = testReadUpdateCorrupt_runner(StorageVariant.FILE)
+
+    @Test
+    fun testReadUpdateCorrupt_okio() = testReadUpdateCorrupt_runner(StorageVariant.OKIO)
+
+    private fun testReadUpdateCorrupt_runner(variant: StorageVariant) =
+        runTest(dispatchTimeoutMs = 10000) {
+            FileOutputStream(testFile).use {
+                OutputStreamWriter(it).write("garbage")
+            }
+            val testData: Bundle = createDataStoreBundle(testFile.absolutePath, variant)
+            val serviceClasses = mapOf(
+                StorageVariant.FILE to InterleavedHandlerUpdateDataFileService::class,
+                StorageVariant.OKIO to InterleavedHandlerUpdateDataOkioService::class
+            )
+            val connection: BlockingServiceConnection =
+                setUpService(mainContext, serviceClasses[variant]!!.java, testData)
+            val corruptionHandler = ReplaceFileCorruptionHandler<FooProto> {
+                signalService(connection)
+                FOO_WITH_TEXT_AND_BOOLEAN
+            }
+            val dataStore: DataStore<FooProto> =
+                createDataStore(testData, dataStoreScope, corruptionHandler, dataStoreContext)
+
+            // Other proc starts TEST_TEXT then waits for signal within handler
             signalService(connection)
-            FOO_WITH_TEXT_AND_BOOLEAN
+
+            assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
+
+            // version file should be ready at this point
+            val sharedCounter = SharedCounter.create {
+                File(testFile.absolutePath + ".version")
+            }
+            // only 1 write should be done to handle the corruption, so version is incremented by 1
+            assertThat(sharedCounter.getValue()).isEqualTo(1)
         }
-        val dataStore: DataStoreImpl<FooProto> =
-            createDataStore(testData, dataStoreScope, corruptionHandler)
 
-        // Other proc starts TEST_TEXT then waits for signal within handler
-        signalService(connection)
-
-        assertThat(dataStore.data.first()).isEqualTo(FOO_WITH_TEXT)
-
-        // version file should be ready at this point
-        val sharedCounter = SharedCounter.create {
-            File(testFile.absolutePath + ".version")
-        }
-        // only 1 write should be done to handle the corruption, so version is incremented by 1
-        assertThat(sharedCounter.getValue()).isEqualTo(1)
-    }
-
-    class InterleavedHandlerUpdateDataService(
+    open class InterleavedHandlerUpdateDataFileService(
         private val scope: TestScope = TestScope(UnconfinedTestDispatcher() + Job())
     ) : DirectTestService() {
         override fun beforeTest(testData: Bundle) {
@@ -493,4 +603,6 @@
             }
         }
     }
+
+    class InterleavedHandlerUpdateDataOkioService : InterleavedHandlerUpdateDataFileService()
 }
\ No newline at end of file
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessFileTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessFileTest.kt
new file mode 100644
index 0000000..24288ef
--- /dev/null
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessFileTest.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.core
+
+import androidx.datastore.FileTestIO
+import androidx.datastore.JavaIOFile
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth
+import java.io.File
+import java.io.IOException
+import java.io.InputStream
+import java.io.OutputStream
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.ObsoleteCoroutinesApi
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.scan
+import kotlinx.coroutines.flow.take
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@OptIn(ExperimentalCoroutinesApi::class, ObsoleteCoroutinesApi::class, FlowPreview::class)
+@InternalCoroutinesApi
+class MultiProcessDataStoreSingleProcessFileTest :
+    MultiProcessDataStoreSingleProcessTest<JavaIOFile>(FileTestIO()) {
+    override fun getJavaFile(file: JavaIOFile): File {
+        return file.file
+    }
+
+    @Test
+    fun testReadUnreadableFile() = runTest {
+        // ensure the file exists by writing into it
+        testFile.file.writeText("")
+        testFile.file.setReadable(false)
+        val result = runCatching {
+            store.data.first()
+        }
+
+        Truth.assertThat(result.exceptionOrNull()).isInstanceOf(IOException::class.java)
+        Truth.assertThat(result.exceptionOrNull()).hasMessageThat().contains("Permission denied")
+    }
+
+    @Test
+    fun testReadAfterTransientBadRead() = runTest {
+        // ensure the file exists by writing into it
+        testFile.file.writeText("")
+        testFile.file.setReadable(false)
+
+        assertThrows<IOException> { store.data.first() }.hasMessageThat()
+            .contains("Permission denied")
+
+        testFile.file.setReadable(true)
+        Truth.assertThat(store.data.first()).isEqualTo(0)
+    }
+
+    @Test
+    fun testMutatingDataStoreFails() = runTest {
+
+        val dataStore = DataStoreImpl(
+            storage = FileStorage(ByteWrapper.ByteWrapperSerializer(), {
+                MultiProcessCoordinator(dataStoreScope.coroutineContext, it)
+            }) { testFile.file },
+            scope = dataStoreScope,
+        )
+
+        assertThrows<IllegalStateException> {
+            dataStore.updateData { input: ByteWrapper ->
+                // mutating our wrapper causes us to fail
+                input.byte = 123.toByte()
+                input
+            }
+        }
+    }
+
+    @Test
+    fun stressTest() = runBlocking {
+        val stressTestFile = getJavaFile(testIO.newTempFile(tempFolder))
+        val testJob = Job()
+        val testScope = CoroutineScope(
+            Dispatchers.IO + testJob
+        )
+        val stressTestStore = DataStoreImpl<Int>(
+            storage = FileStorage(
+                object : Serializer<Int> {
+                    override val defaultValue: Int
+                        get() = 0
+
+                    override suspend fun readFrom(input: InputStream): Int {
+                        return input.reader(Charsets.UTF_8).use {
+                            it.readText().toIntOrNull() ?: defaultValue
+                        }
+                    }
+
+                    override suspend fun writeTo(t: Int, output: OutputStream) {
+                        output.writer(Charsets.UTF_8).use {
+                            it.write(t.toString())
+                            it.flush()
+                        }
+                    }
+                },
+                coordinatorProducer = {
+                    MultiProcessCoordinator(testScope.coroutineContext, it)
+                },
+                produceFile = { stressTestFile }
+            ),
+            scope = testScope,
+            initTasksList = emptyList()
+        )
+        val limit = 1_000
+        stressTestStore.updateData { 0 }
+        val reader = async(Dispatchers.IO + testJob) {
+            stressTestStore.data.scan(0) { prev, next ->
+                check(next >= prev) {
+                    "check failed: $prev / $next"
+                }
+                next
+            }.take(limit - 200).collect() // we can drop some intermediate values, it is fine
+        }
+        val writer = async {
+            repeat(limit) {
+                stressTestStore.updateData {
+                    it + 1
+                }
+            }
+        }
+        listOf(reader, writer).awaitAll()
+        testJob.cancelAndJoin()
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessOkioTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessOkioTest.kt
new file mode 100644
index 0000000..d71d516
--- /dev/null
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessOkioTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.core
+
+import androidx.datastore.OkioPath
+import androidx.datastore.OkioTestIO
+import java.io.File
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.ObsoleteCoroutinesApi
+
+@OptIn(ExperimentalCoroutinesApi::class, ObsoleteCoroutinesApi::class, FlowPreview::class)
+@InternalCoroutinesApi
+class MultiProcessDataStoreSingleProcessOkioTest :
+    MultiProcessDataStoreSingleProcessTest<OkioPath>(OkioTestIO()) {
+    override fun getJavaFile(file: OkioPath): File {
+        return file.path.toFile()
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreTest.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
similarity index 83%
rename from datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreTest.kt
rename to datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
index cb0b049..0ffe3d0 100644
--- a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/MultiProcessDataStoreSingleProcessTest.kt
@@ -17,6 +17,8 @@
 package androidx.datastore.core
 
 import android.os.StrictMode
+import androidx.datastore.TestFile
+import androidx.datastore.TestIO
 import androidx.datastore.TestingSerializerConfig
 import androidx.datastore.core.handlers.NoOpCorruptionHandler
 import androidx.test.filters.FlakyTest
@@ -24,7 +26,6 @@
 import androidx.testutils.assertThrows
 import com.google.common.truth.Truth.assertThat
 import java.io.File
-import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
 import java.util.concurrent.Executors
@@ -32,6 +33,7 @@
 import java.util.concurrent.atomic.AtomicInteger
 import kotlin.coroutines.AbstractCoroutineContextElement
 import kotlin.coroutines.CoroutineContext
+import kotlin.random.Random
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineScope
@@ -41,13 +43,10 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.cancelAndJoin
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.scan
 import kotlinx.coroutines.flow.take
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.job
@@ -59,9 +58,7 @@
 import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.withContext
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TemporaryFolder
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
@@ -73,28 +70,32 @@
 @ExperimentalCoroutinesApi
 @LargeTest
 @RunWith(JUnit4::class)
-class MultiProcessDataStoreTest {
-    @get:Rule
-    val tempFolder = TemporaryFolder()
-
-    private lateinit var store: DataStore<Byte>
+abstract class MultiProcessDataStoreSingleProcessTest<F : TestFile>(
+    protected val testIO: TestIO<F, *>
+) {
+    protected lateinit var store: DataStore<Byte>
     private lateinit var serializerConfig: TestingSerializerConfig
-    private lateinit var testingSerializer: TestingSerializer
-    private lateinit var testFile: File
-    private lateinit var dataStoreScope: TestScope
+    protected lateinit var testFile: F
+    protected lateinit var tempFolder: F
+    protected lateinit var dataStoreScope: TestScope
+
+    abstract fun getJavaFile(file: F): File
 
     private fun newDataStore(
-        file: File = testFile,
-        serializer: Serializer<Byte> = testingSerializer,
+        file: TestFile = testFile,
         scope: CoroutineScope = dataStoreScope,
         initTasksList: List<suspend (api: InitializerApi<Byte>) -> Unit> = listOf(),
         corruptionHandler: CorruptionHandler<Byte> = NoOpCorruptionHandler<Byte>()
     ): DataStore<Byte> {
         return DataStoreImpl(
-            storage = FileStorage(
-                serializer,
-                { MultiProcessCoordinator(scope.coroutineContext, it) }
-            ) { file },
+            storage = testIO.getStorage(
+                serializerConfig,
+                {
+                    MultiProcessCoordinator(
+                        dataStoreScope.coroutineContext,
+                        getJavaFile(testFile)
+                    )
+                }) { file },
             scope = scope,
             initTasksList = initTasksList,
             corruptionHandler = corruptionHandler
@@ -104,15 +105,14 @@
     @Before
     fun setUp() {
         serializerConfig = TestingSerializerConfig()
-        testingSerializer = TestingSerializer(serializerConfig)
-        testFile = tempFolder.newFile()
+        tempFolder = testIO.tempDir()
+        testFile = testIO.newTempFile(tempFolder)
         dataStoreScope = TestScope(UnconfinedTestDispatcher() + Job())
-        store =
-            newDataStore(
-                testFile,
-                testingSerializer,
-                scope = dataStoreScope
-            )
+        store = testIO.getStore(
+            serializerConfig,
+            dataStoreScope,
+            { MultiProcessCoordinator(dataStoreScope.coroutineContext, getJavaFile(testFile)) }
+        ) { testFile }
     }
 
     @Test
@@ -133,28 +133,6 @@
     }
 
     @Test
-    fun testReadUnreadableFile() = runTest {
-        testFile.setReadable(false)
-        val result = runCatching {
-            store.data.first()
-        }
-
-        assertThat(result.exceptionOrNull()).isInstanceOf(IOException::class.java)
-        assertThat(result.exceptionOrNull()).hasMessageThat().contains("Permission denied")
-    }
-
-    @Test
-    fun testReadAfterTransientBadRead() = runTest {
-        testFile.setReadable(false)
-
-        assertThrows<IOException> { store.data.first() }.hasMessageThat()
-            .contains("Permission denied")
-
-        testFile.setReadable(true)
-        assertThat(store.data.first()).isEqualTo(0)
-    }
-
-    @Test
     fun testScopeCancelledWithActiveFlow() = runTest {
         val storeScope = CoroutineScope(Job())
         val dataStore = newDataStore(scope = storeScope)
@@ -215,7 +193,7 @@
 
     @Test
     fun testReadAfterTransientBadWrite() = runBlocking {
-        val file = tempFolder.newFile()
+        val file = testIO.newTempFile(tempFolder)
         runTest {
             val store = newDataStore(file, scope = backgroundScope)
             store.updateData { 1 }
@@ -231,8 +209,13 @@
 
     @Test
     fun testWriteToNonExistentDir() = runBlocking {
-        val fileInNonExistentDir =
-            File(tempFolder.newFolder(), "/this/does/not/exist/foo.tst")
+        val fileInNonExistentDir = testIO.newTempFile(
+            testIO.tempDir(
+                "/this/does/not/exist",
+                makeDirs = false,
+                parentDir = testIO.tempDir()
+            )
+        )
         runTest {
             val newStore = newDataStore(fileInNonExistentDir, scope = backgroundScope)
 
@@ -249,18 +232,16 @@
 
     @Test
     fun testReadFromNonExistentFile() = runTest {
-        val nonExistentFile = tempFolder.newFile()
-        assertThat(nonExistentFile.delete()).isTrue()
-        val newStore = newDataStore(nonExistentFile)
+        testFile.deleteIfExists()
+        val newStore = newDataStore(testFile)
         assertThat(newStore.data.first()).isEqualTo(0)
     }
 
     @Test
     fun testWriteToDirFails() = runTest {
-        val directoryFile =
-            File(tempFolder.newFolder(), "/this/is/a/directory")
-        directoryFile.mkdirs()
-        assertThat(directoryFile.isDirectory).isTrue()
+        val directoryFile = testIO.tempDir("/this/is/a${Random.nextInt()}/directory")
+
+        assertThat(testIO.isDirectory(directoryFile))
 
         val newStore = newDataStore(directoryFile)
         assertThrows<IOException> { newStore.data.first() }
@@ -277,14 +258,16 @@
             testFile
         }
 
-        val newStore = DataStoreImpl(
-            storage = FileStorage(
-                testingSerializer,
-                { MultiProcessCoordinator(dataStoreScope.coroutineContext, it) },
-                fileProducer
-            ),
-            scope = dataStoreScope,
-            initTasksList = listOf()
+        val newStore = testIO.getStore(
+            serializerConfig,
+            dataStoreScope,
+            {
+                MultiProcessCoordinator(
+                    dataStoreScope.coroutineContext,
+                    getJavaFile(fileProducer())
+                )
+            },
+            fileProducer
         )
 
         assertThrows<IOException> { newStore.data.first() }.hasMessageThat().isEqualTo(
@@ -315,6 +298,9 @@
 
     @Test
     fun testWriteAfterTransientBadRead() = runTest {
+        testFile.createIfNotExists()
+        assertThat(testFile.exists()).isTrue()
+
         serializerConfig.failingRead = true
 
         assertThrows<IOException> { store.data.first() }
@@ -327,6 +313,9 @@
 
     @Test
     fun testWriteWithBadReadFails() = runTest {
+        testFile.createIfNotExists()
+        assertThat(testFile.exists()).isTrue()
+
         serializerConfig.failingRead = true
 
         assertThrows<IOException> { store.updateData { 1 } }
@@ -624,61 +613,6 @@
     }
 
     @Test
-    fun stressTest() = runBlocking {
-        val stressTestFile = tempFolder.newFile()
-        val testJob = Job()
-        val testScope = CoroutineScope(
-            Dispatchers.IO + testJob
-        )
-        val stressTestStore = DataStoreImpl<Int>(
-            storage = FileStorage(
-                object : Serializer<Int> {
-                    override val defaultValue: Int
-                        get() = 0
-
-                    override suspend fun readFrom(input: InputStream): Int {
-                        return input.reader(Charsets.UTF_8).use {
-                            it.readText().toIntOrNull() ?: defaultValue
-                        }
-                    }
-
-                    override suspend fun writeTo(t: Int, output: OutputStream) {
-                        output.writer(Charsets.UTF_8).use {
-                            it.write(t.toString())
-                            it.flush()
-                        }
-                    }
-                },
-                coordinatorProducer = {
-                    MultiProcessCoordinator(testScope.coroutineContext, it)
-                },
-                produceFile = { stressTestFile }
-            ),
-            scope = testScope,
-            initTasksList = emptyList()
-        )
-        val limit = 1_000
-        stressTestStore.updateData { 0 }
-        val reader = async(Dispatchers.IO + testJob) {
-            stressTestStore.data.scan(0) { prev, next ->
-                check(next >= prev) {
-                    "check failed: $prev / $next"
-                }
-                next
-            }.take(limit - 200).collect() // we can drop some intermediate values, it is fine
-        }
-        val writer = async {
-            repeat(limit) {
-                stressTestStore.updateData {
-                    it + 1
-                }
-            }
-        }
-        listOf(reader, writer).awaitAll()
-        testJob.cancelAndJoin()
-    }
-
-    @Test
     fun testMultipleFlowsReceiveData() = runTest {
         val flowOf8 = store.data.take(8)
 
@@ -857,37 +791,15 @@
     }
 
     @Test
-    fun testMutatingDataStoreFails() = runTest {
-
-        val dataStore = DataStoreImpl(
-            storage = FileStorage(ByteWrapper.ByteWrapperSerializer(), {
-                MultiProcessCoordinator(dataStoreScope.coroutineContext, it)
-            }) { testFile },
-            scope = dataStoreScope,
-        )
-
-        assertThrows<IllegalStateException> {
-            dataStore.updateData { input: ByteWrapper ->
-                // mutating our wrapper causes us to fail
-                input.byte = 123.toByte()
-                input
-            }
-        }
-    }
-
-    @Test
     fun testDefaultValueUsedWhenNoDataOnDisk() = runTest {
-        val dataStore = DataStoreImpl(
-            storage = FileStorage(
-                TestingSerializer(TestingSerializerConfig(defaultValue = 99)),
-                { MultiProcessCoordinator(dataStoreScope.coroutineContext, it) }
-            ) {
-                testFile
-            },
-            scope = dataStoreScope
-        )
+        testFile.deleteIfExists()
 
-        assertThat(testFile.delete()).isTrue()
+        val dataStore = testIO.getStore(
+            TestingSerializerConfig(defaultValue = 99),
+            dataStoreScope,
+            { MultiProcessCoordinator(dataStoreScope.coroutineContext, getJavaFile(testFile)) }) {
+            testFile
+        }
 
         assertThat(dataStore.data.first()).isEqualTo(99)
     }
@@ -983,7 +895,7 @@
 
     @Test
     fun testCreateDuplicateActiveDataStore() = runTest {
-        val file = tempFolder.newFile()
+        val file = testIO.newTempFile(tempFolder)
         val dataStore = newDataStore(file = file, scope = CoroutineScope(Job()))
 
         dataStore.data.first()
@@ -997,7 +909,7 @@
 
     @Test
     fun testCreateDataStore_withSameFileAsInactiveDataStore() = runTest {
-        val file = tempFolder.newFile()
+        val file = testIO.newTempFile(tempFolder)
         val scope1 = CoroutineScope(Job())
         val dataStore1 = newDataStore(file = file, scope = scope1)
 
diff --git a/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/ProtoOkioSerializer.kt b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/ProtoOkioSerializer.kt
new file mode 100644
index 0000000..29540b5
--- /dev/null
+++ b/datastore/datastore-core/src/androidTest/java/androidx/datastore/core/ProtoOkioSerializer.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.datastore.core
+
+import androidx.datastore.core.okio.OkioSerializer
+import com.google.protobuf.ExtensionRegistryLite
+import com.google.protobuf.InvalidProtocolBufferException
+import com.google.protobuf.MessageLite
+import okio.BufferedSink
+import okio.BufferedSource
+
+/** OkioSerializer for using DataStore with protos. */
+internal class ProtoOkioSerializer<T : MessageLite>(
+    /** The default proto of this type, obtained via {@code T.getDefaultInstance()} */
+    override val defaultValue: T,
+    /**
+     *  Set the extensionRegistryLite to use when deserializing T. If no extension registry is
+     *  necessary, use {@code ExtensionRegistryLite.getEmptyRegistry()}.
+     */
+    private val extensionRegistryLite: ExtensionRegistryLite =
+        ExtensionRegistryLite.getEmptyRegistry()
+) : OkioSerializer<T> {
+    @Suppress("UNCHECKED_CAST")
+    override suspend fun readFrom(source: BufferedSource): T {
+        try {
+            return defaultValue.parserForType.parseFrom(
+                source.inputStream(),
+                extensionRegistryLite
+            ) as T
+        } catch (invalidProtocolBufferException: InvalidProtocolBufferException) {
+            throw CorruptionException(
+                "Cannot read proto.", invalidProtocolBufferException
+            )
+        }
+    }
+
+    override suspend fun writeTo(t: T, sink: BufferedSink) {
+        t.writeTo(sink.outputStream())
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/DataMigrationInitializerTest.kt b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/DataMigrationInitializerTest.kt
index d30f1d9..ccc6edb 100644
--- a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/DataMigrationInitializerTest.kt
+++ b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/DataMigrationInitializerTest.kt
@@ -143,7 +143,8 @@
         )
 
         val storage = testIO.getStorage(
-            TestingSerializerConfig(failingWrite = true)
+            TestingSerializerConfig(failingWrite = true),
+            { createSingleProcessCoordinator() }
         ) { testIO.newTempFile() }
         val store = newDataStore(
             initTasksList = listOf(
@@ -194,7 +195,8 @@
     private fun newDataStore(
         initTasksList: List<suspend (api: InitializerApi<Byte>) -> Unit> = listOf(),
         storage: Storage<Byte> = testIO.getStorage(
-            TestingSerializerConfig()
+            TestingSerializerConfig(),
+            { createSingleProcessCoordinator() }
         )
     ): DataStore<Byte> {
         return DataStoreImpl(
diff --git a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
index 454ed64..dfa3273 100644
--- a/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
+++ b/datastore/datastore-core/src/commonTest/kotlin/androidx/datastore/core/SingleProcessDataStoreTest.kt
@@ -68,7 +68,11 @@
         tempFolder = testIO.tempDir()
         testFile = testIO.newTempFile(tempFolder)
         dataStoreScope = TestScope(UnconfinedTestDispatcher())
-        store = testIO.getStore(serializerConfig, dataStoreScope) { testFile }
+        store = testIO.getStore(
+            serializerConfig,
+            dataStoreScope,
+            { createSingleProcessCoordinator() }
+        ) { testFile }
     }
 
     fun doTest(initDataStore: Boolean = false, test: suspend TestScope.() -> Unit) {
@@ -102,7 +106,10 @@
     @Test
     fun testScopeCancelledWithActiveFlow() = doTest {
         val storeScope = CoroutineScope(Job())
-        val store = testIO.getStore(serializerConfig, storeScope) { testFile }
+        val store = testIO.getStore(
+            serializerConfig,
+            storeScope,
+            { createSingleProcessCoordinator() }) { testFile }
 
         val collection = async {
             store.data.take(2).collect {
@@ -175,7 +182,8 @@
     @Test
     fun testWriteToNonExistentDir() = doTest {
         val fileInNonExistentDir = testIO.newTempFile(
-            testIO.tempDir("/this/does/not/exist", makeDirs = false))
+            testIO.tempDir("/this/does/not/exist", makeDirs = false)
+        )
 
         coroutineScope {
             val newStore = newDataStore(fileInNonExistentDir, scope = this)
@@ -193,7 +201,8 @@
 
     @Test
     fun testReadFromNonExistentFile() = doTest {
-        assertThat(testFile.delete()).isTrue()
+        // TODO remove deleteIfExists after b/276983736
+        testFile.deleteIfExists()
         val newStore = newDataStore(testFile)
         assertThat(newStore.data.first()).isEqualTo(0)
     }
@@ -218,7 +227,12 @@
             }
             testFile
         }
-        val newStore = testIO.getStore(serializerConfig, dataStoreScope, fileProducer)
+        val newStore = testIO.getStore(
+            serializerConfig,
+            dataStoreScope,
+            { createSingleProcessCoordinator() },
+            fileProducer
+        )
 
         assertThrows<IOException> { newStore.data.first() }.hasMessageThat().isEqualTo(
             "Exception when producing file"
@@ -689,11 +703,11 @@
 
     @Test
     fun testDefaultValueUsedWhenNoDataOnDisk() = doTest {
+        testFile.deleteIfExists()
         val dataStore = newDataStore(
             serializerConfig = TestingSerializerConfig(defaultValue = 99),
-            scope = dataStoreScope)
-
-        assertThat(testFile.delete()).isTrue()
+            scope = dataStoreScope
+        )
 
         assertThat(dataStore.data.first()).isEqualTo(99)
     }
@@ -878,6 +892,7 @@
             file = testIO.newTempFile(),
             scope = datastoreScope.backgroundScope
         )
+
         suspend fun <R> runAndPumpInStore(block: suspend () -> R): R {
             val async = datastoreScope.async { block() }
             datastoreScope.runCurrent()
@@ -959,7 +974,7 @@
         corruptionHandler: CorruptionHandler<Byte> = NoOpCorruptionHandler<Byte>()
     ): DataStore<Byte> {
         return DataStoreImpl(
-            testIO.getStorage(serializerConfig) { file },
+            testIO.getStorage(serializerConfig, { createSingleProcessCoordinator() }) { file },
             scope = scope,
             initTasksList = initTasksList,
             corruptionHandler = corruptionHandler
diff --git a/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt b/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
index 91e35d0..ace5688 100644
--- a/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
+++ b/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
@@ -32,6 +32,9 @@
  * file location.
  *
  * @param serializer The serializer that can write <T> to and from a byte array.
+ * @param coordinatorProducer The producer to provide [InterProcessCoordinator] that coordinates IO
+ * operations across processes if needed. By default it provides single process coordinator, which
+ * doesn't support cross process use cases.
  * @param produceFile The file producer that returns the file that will be read and written.
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
diff --git a/datastore/datastore-core/src/jvmTest/kotlin/androidx/datastore/core/JvmTests.kt b/datastore/datastore-core/src/jvmTest/kotlin/androidx/datastore/core/JvmTests.kt
index 10b6ea1..033a8c9 100644
--- a/datastore/datastore-core/src/jvmTest/kotlin/androidx/datastore/core/JvmTests.kt
+++ b/datastore/datastore-core/src/jvmTest/kotlin/androidx/datastore/core/JvmTests.kt
@@ -37,7 +37,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @InternalCoroutinesApi
-class SingleProcessDatastoreJavaTest : SingleProcessDataStoreTest<JavaIOFile>(FileTestIO()) {
+class SingleProcessDataStoreJavaTest : SingleProcessDataStoreTest<JavaIOFile>(FileTestIO()) {
 
     @Test
     fun testMutatingDataStoreFails() = doTest {
@@ -78,6 +78,8 @@
 
     @Test
     fun testReadUnreadableFile() = doTest {
+        // ensure the file exists by writing into it
+        testFile.file.writeText("")
         testFile.file.setReadable(false)
         val result = runCatching {
             store.data.first()
@@ -89,6 +91,8 @@
 
     @Test
     fun testReadAfterTransientBadRead() = doTest {
+        // ensure the file exists by writing into it
+        testFile.file.writeText("")
         testFile.file.setReadable(false)
 
         assertThrows<IOException> { store.data.first() }.hasMessageThat()
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index acd42b2..59d4db0 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -17,6 +17,7 @@
 Daemon will be stopped at the end of the build
 # > Configure project :appsearch:appsearch\-local\-backend
 Configuration on demand is an incubating feature\.
+Calculating task graph as configuration cache cannot be reused because an input to ClasspathEntrySnapshotTransform\: \$OUT_DIR\/buildSrc\/jetpad\-integration\/build\/libs\/jetpad\-integration\.jar has changed\.
 Calculating task graph as configuration cache cannot be reused because the set of Gradle properties has changed\.
 You are using legacy USE_ANDROIDX_REMOTE_BUILD_CACHE=true type, this cache has been turned down, so you are \*not\* using a remote cache\. Please move to the new cache using http://go/androidx\-dev\#remote\-build\-cache
 Configuration cache is an incubating feature\.
@@ -74,10 +75,11 @@
 Html results of .* zipped into.*\.zip
 # b/230127926
 [0-9]+ problem.* found storing the configuration cache.*
+See https://docs\.gradle\.org/[0-9]+\.[0-9]+/userguide/configuration_cache\.html\#config_cache:requirements:task_access
 plus [0-9]+ more problems\. Please see the report for details\.
 # https://youtrack.jetbrains.com/issue/KT-43293 fixed in Kotlin 1.8.0
 \- Task \`((\:[a-z1-9-]+)+)?\:[a-zA-Z1-9]+\` of type \`org\.jetbrains(\.[a-zA-Z]+)+\.(CInteropCommonizerTask|KotlinNativeCompile|KotlinNativeLink|KotlinNativeHostTest|CInteropMetadataDependencyTransformationTask|GenerateProjectStructureMetadata|TransformKotlinGranularMetadata|NativeDistributionCommonizerTask|transformNonJvmMainDependenciesMetadata|MetadataDependencyTransformationTask)\`\: invocation of \'Task\.project\' at execution time is unsupported\.
-\- Task \`((\:[a-z1-9-]+)+)?\:[a-zA-Z1-9]+\` of type \`org\.jetbrains\.kotlin\.gradle\.targets\.native\.internal\.(CInteropMetadataDependencyTransformationTask|NativeDistributionCommonizerTask)\`: cannot serialize object of type \'org\.gradle(\.[a-zA-Z]+)+\'\, a subtype of \'org\.gradle(\.[a-zA-Z]+)+\'\, as these are not supported with the configuration cache\.
+\- Task \`((\:[a-z1-9-]+)+)?\:[a-zA-Z1-9]+\` of type \`org\.jetbrains(\.[a-zA-Z]+)+\.(CInteropMetadataDependencyTransformationTask|NativeDistributionCommonizerTask)\`: cannot serialize object of type \'org\.gradle(\.[a-zA-Z]+)+\'\, a subtype of \'org\.gradle(\.[a-zA-Z]+)+\'\, as these are not supported with the configuration cache\.
 # https://youtrack.jetbrains.com/issue/KT-54627
 \- Task \`\:commonizeNativeDistribution\` of type \`org\.jetbrains\.kotlin\.gradle\.targets\.native\.internal\.NativeDistributionCommonizerTask\`\: error writing value of type \'java\.util\.concurrent\.locks\.ReentrantLock\'
 See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:use_project_during_execution
@@ -802,6 +804,7 @@
 public abstract java\.util\.List<androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameEntity> jvmQuery\(\);
 public abstract androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameDao jvmDao\(\);
 \^
+Note: \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/TitleChip\.java has additional uses or overrides of a deprecated API\.
 \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout\.java:[0-9]+: warning: \[deprecation\] CompactChip in androidx\.wear\.tiles\.material has been deprecated
 Note: \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/Button\.java has additional uses or overrides of a deprecated API\.
 \$SUPPORT/wear/tiles/tiles\-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator\.java:[0-9]+: warning: \[deprecation\] ButtonDefaults in androidx\.wear\.tiles\.material has been deprecated
@@ -953,6 +956,8 @@
 Please wait while Kotlin/Native compiler .* is being installed\.
 Unpack Kotlin/Native compiler to .*
 Download file:\.\./\.\./.*
+Download kotlin\-native\-prebuilt\-.*.gz finished\, took [0-9]+ s [0-9]+ ms
+Download kotlin\-native\-prebuilt\-.*.gz finished\, took [0-9]+ ms
 Downloading native dependencies \(LLVM, sysroot etc\)\. This is a one\-time action performed only on the first run of the compiler\.
 Extracting dependency: .*\.konan/cache.*
 # New memory model does not work with compiler caches yet:
@@ -1005,3 +1010,21 @@
 import static androidx\.wear\.tiles\.material\.Typography\.TYPOGRAPHY_BODY[0-9]+;
 # > Task :wear:tiles:tiles-material:compileDebugAndroidTestJavaWithJavac
 \$SUPPORT/wear/tiles/tiles\-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator\.java:[0-9]+: warning: \[deprecation\] Button in androidx\.wear\.tiles\.material has been deprecated
+# > Configure project :androidx-demos
+WARNING: The option setting 'android\.experimental\.disableCompileSdkChecks=true' is experimental\.
+The current default is 'false'\.
+# > Task :camera:camera-video:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/camera/camera\-video/src/androidTest/java/androidx/camera/video/internal/audio/AudioStreamImplTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+# > Task :benchmark:benchmark-macro:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/benchmark/benchmark\-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+# > Task :graphics:graphics-core:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/graphics/graphics\-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+w: file://\$SUPPORT/graphics/graphics\-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlWrapperTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+# > Task :compose:foundation:foundation:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldKeyboardScrollableInteractionTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/AbstractSelectionMagnifierTests\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionContainerMagnifierTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionHandlePopupPositionTest\.kt:[0-9]+:[0-9]+ 'getter for windowLayoutParams: EspressoOptional<WindowManager\.LayoutParams!>!' is deprecated\. Deprecated in Java
+w: file://\$SUPPORT/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/TextFieldVisualTransformationMagnifierTest\.kt:[0-9]+:[0-9]+ 'RequiresDevice' is deprecated\. Deprecated in Java
+# > Task :compose:ui:ui:compileDebugAndroidTestKotlin
+w: file://\$SUPPORT/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/window/PopupTestUtils\.kt:[0-9]+:[0-9]+ 'getter for windowLayoutParams: EspressoOptional<WindowManager\.LayoutParams!>!' is deprecated\. Deprecated in Java
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt
index cc106b9..57f1259 100644
--- a/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt
@@ -22,6 +22,7 @@
 import org.jetbrains.kotlin.com.google.common.annotations.VisibleForTesting
 import java.security.MessageDigest
 import java.util.Locale
+import java.util.concurrent.ConcurrentHashMap
 
 /**
  * A [DownloadObserver] that will save all files into the given repository folders.
@@ -39,12 +40,13 @@
 ) : DownloadObserver {
     private val logger = logger("LocalMavenRepoDownloader")
     private val licenseDownloader = LicenseDownloader(enableGithubApi = false)
-    private val writtenFiles = mutableSetOf<Path>()
+    private val writtenFilesMap: MutableMap<Path, Boolean> = ConcurrentHashMap<Path, Boolean>()
+    fun writtenFiles(): Set<Path> = writtenFilesMap.keys
 
     /**
      * Returns the list of files we've downloaded.
      */
-    fun getDownloadedFiles() = writtenFiles.sorted().distinct()
+    fun getDownloadedFiles() = writtenFiles()
 
     override fun onDownload(path: String, bytes: ByteArray) {
         if (path.substringAfterLast('.') in checksumExtensions) {
@@ -118,7 +120,7 @@
         file: Path,
         contents: ByteArray
     ) {
-        writtenFiles.add(file.normalized())
+        writtenFilesMap.put(file.normalized(), true)
         file.parent?.let(fileSystem::createDirectories)
         write(
             file = file,
@@ -144,7 +146,7 @@
      * might delete files that were resolved from the local repository.
      */
     fun cleanupLocalRepositories() {
-        val folders = writtenFiles.filter {
+        val folders = writtenFiles().filter {
             val isDirectory = fileSystem.metadata(it).isDirectory
             !isDirectory && it.name.substringAfterLast(".") in EXTENSIONS_FOR_CLENAUP
         }.mapNotNull {
@@ -160,7 +162,7 @@
                 "Cleaning up $folder ($index of ${folders.size})"
             }
             fileSystem.list(folder).forEach { candidateToDelete ->
-                if (!writtenFiles.contains(candidateToDelete.normalized())) {
+                if (!writtenFiles().contains(candidateToDelete.normalized())) {
                     logger.trace {
                         "Deleting $candidateToDelete since it is not re-downloaded"
                     }
@@ -255,4 +257,4 @@
             return signatureFileName to resultBytes
         }
     }
-}
\ No newline at end of file
+}
diff --git a/development/project-creator/compose-template/groupId/artifactId/build.gradle b/development/project-creator/compose-template/groupId/artifactId/build.gradle
index 01a8626..a47774d 100644
--- a/development/project-creator/compose-template/groupId/artifactId/build.gradle
+++ b/development/project-creator/compose-template/groupId/artifactId/build.gradle
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
+import androidx.build.AndroidXComposePlugin
 import androidx.build.LibraryType
-import androidx.build.KmpPlatformsKt
 
 plugins {
     id("AndroidXPlugin")
@@ -24,77 +24,68 @@
     id("org.jetbrains.kotlin.android")
 }
 
-def desktopEnabled = KmpPlatformsKt.enableDesktop(project)
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
 
-androidXMultiplatform {
-    android()
-    if (desktopEnabled) desktop()
+dependencies {
 
-    sourceSets {
-        commonMain {
-            dependencies {
+
+    if(!AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block below
+         */
+        implementation(libs.kotlinStdlibCommon)
+
+        api("androidx.annotation:annotation:1.1.0")
+
+        testImplementation(libs.testRules)
+        testImplementation(libs.testRunner)
+        testImplementation(libs.junit)
+        testImplementation(libs.truth)
+
+        androidTestImplementation(libs.testRules)
+        androidTestImplementation(libs.testRunner)
+        androidTestImplementation(libs.junit)
+        androidTestImplementation(libs.truth)
+    }
+}
+
+if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
+    androidXComposeMultiplatform {
+        android()
+        desktop()
+    }
+
+    kotlin {
+        /*
+         * When updating dependencies, make sure to make the an an analogous update in the
+         * corresponding block above
+         */
+        sourceSets {
+            commonMain.dependencies {
                 implementation(libs.kotlinStdlibCommon)
             }
-        }
-        androidMain.dependencies {
-        }
 
-        commonTest {
-            dependencies {
-            }
-        }
-
-        jvmMain {
-            dependsOn(commonMain)
-            dependencies {
-                implementation(libs.testRules)
-                implementation(libs.testRunner)
-                implementation(libs.junit)
-                implementation(libs.truth)
-            }
-        }
-
-
-        androidMain {
-            dependsOn(jvmMain)
-            dependencies {
+            androidMain.dependencies {
                 api("androidx.annotation:annotation:1.1.0")
             }
-        }
 
-        if (desktopEnabled) {
-            desktopMain {
-                dependsOn(jvmMain)
-                dependencies {
-                    implementation(libs.kotlinStdlib)
-                }
+            desktopMain.dependencies {
+                implementation(libs.kotlinStdlib)
             }
-        }
 
-        jvmTest {
-            dependsOn(commonTest)
-            dependsOn(jvmMain)
-            dependencies {
-            }
-        }
-
-        androidAndroidTest {
-            dependsOn(jvmTest)
-            dependsOn(androidMain)
-            dependencies {
+            test.dependencies {
                 implementation(libs.testRules)
                 implementation(libs.testRunner)
                 implementation(libs.junit)
                 implementation(libs.truth)
             }
-        }
 
-        if (desktopEnabled) {
-            desktopTest {
-                dependsOn(jvmTest)
-                dependsOn(desktopMain)
-                dependencies {
-                }
+            androidAndroidTest.dependencies {
+                implementation(libs.testRules)
+                implementation(libs.testRunner)
+                implementation(libs.junit)
+                implementation(libs.truth)
             }
         }
     }
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index ae580c2..6a2a82b 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -8,10 +8,10 @@
 }
 
 dependencies {
-    docs("androidx.activity:activity:1.8.0-alpha02")
-    docs("androidx.activity:activity-compose:1.8.0-alpha02")
-    samples("androidx.activity:activity-compose-samples:1.8.0-alpha02")
-    docs("androidx.activity:activity-ktx:1.8.0-alpha02")
+    docs("androidx.activity:activity:1.8.0-alpha03")
+    docs("androidx.activity:activity-compose:1.8.0-alpha03")
+    samples("androidx.activity:activity-compose-samples:1.8.0-alpha03")
+    docs("androidx.activity:activity-ktx:1.8.0-alpha03")
     docs("androidx.ads:ads-identifier:1.0.0-alpha05")
     docs("androidx.ads:ads-identifier-common:1.0.0-alpha05")
     docs("androidx.ads:ads-identifier-provider:1.0.0-alpha05")
@@ -120,12 +120,12 @@
     docs("androidx.core:core-role:1.2.0-alpha01")
     docs("androidx.core:core-animation:1.0.0-beta02")
     docs("androidx.core:core-animation-testing:1.0.0-beta01")
-    docs("androidx.core:core:1.12.0-alpha01")
-    docs("androidx.core:core-ktx:1.12.0-alpha01")
+    docs("androidx.core:core:1.12.0-alpha03")
+    docs("androidx.core:core-ktx:1.12.0-alpha03")
     docs("androidx.core:core-splashscreen:1.1.0-alpha01")
-    docs("androidx.core:core-testing:1.11.0-alpha02")
-    docs("androidx.credentials:credentials:1.2.0-alpha02")
-    docs("androidx.credentials:credentials-play-services-auth:1.2.0-alpha02")
+    docs("androidx.core:core-testing:1.12.0-alpha03")
+    docs("androidx.credentials:credentials:1.2.0-alpha03")
+    docs("androidx.credentials:credentials-play-services-auth:1.2.0-alpha03")
     docs("androidx.credentials:credentials-provider:1.0.0-alpha03")
     docs("androidx.cursoradapter:cursoradapter:1.0.0")
     docs("androidx.customview:customview:1.2.0-alpha02")
@@ -236,8 +236,8 @@
     docs("androidx.media3:media3-transformer:1.0.0")
     docs("androidx.media3:media3-ui:1.0.0")
     docs("androidx.media3:media3-ui-leanback:1.0.0")
-    docs("androidx.mediarouter:mediarouter:1.6.0-alpha02")
-    docs("androidx.mediarouter:mediarouter-testing:1.6.0-alpha02")
+    docs("androidx.mediarouter:mediarouter:1.6.0-alpha03")
+    docs("androidx.mediarouter:mediarouter-testing:1.6.0-alpha03")
     docs("androidx.metrics:metrics-performance:1.0.0-alpha04")
     docs("androidx.navigation:navigation-common:2.6.0-alpha09")
     docs("androidx.navigation:navigation-common-ktx:2.6.0-alpha09")
@@ -319,25 +319,25 @@
     docs("androidx.sqlite:sqlite-ktx:2.4.0-alpha01")
     docs("androidx.startup:startup-runtime:1.2.0-alpha02")
     docs("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
-    docs("androidx.test:core:1.5.0")
-    docs("androidx.test:core-ktx:1.5.0")
-    docs("androidx.test:monitor:1.6.1")
-    docs("androidx.test:rules:1.5.0")
-    docs("androidx.test:runner:1.5.2")
-    docs("androidx.test.espresso:espresso-accessibility:3.5.1")
-    docs("androidx.test.espresso:espresso-contrib:3.5.1")
-    docs("androidx.test.espresso:espresso-core:3.5.1")
-    docs("androidx.test.espresso:espresso-device:1.0.0-alpha03")
-    docs("androidx.test.espresso:espresso-idling-resource:3.5.1")
-    docs("androidx.test.espresso:espresso-intents:3.5.1")
-    docs("androidx.test.espresso:espresso-remote:3.5.1")
-    docs("androidx.test.espresso:espresso-web:3.5.1")
-    docs("androidx.test.espresso.idling:idling-concurrent:3.5.1")
-    docs("androidx.test.espresso.idling:idling-net:3.5.1")
-    docs("androidx.test.ext:junit:1.1.5")
-    docs("androidx.test.ext:junit-ktx:1.1.5")
-    docs("androidx.test.ext:truth:1.5.0")
-    docs("androidx.test.services:storage:1.4.2")
+    docs("androidx.test:core:1.6.0-alpha01")
+    docs("androidx.test:core-ktx:1.6.0-alpha01")
+    docs("androidx.test:monitor:1.7.0-alpha01")
+    docs("androidx.test:rules:1.6.0-alpha01")
+    docs("androidx.test:runner:1.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-accessibility:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-contrib:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-core:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-device:1.0.0-alpha04")
+    docs("androidx.test.espresso:espresso-idling-resource:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-intents:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-remote:3.6.0-alpha01")
+    docs("androidx.test.espresso:espresso-web:3.6.0-alpha01")
+    docs("androidx.test.espresso.idling:idling-concurrent:3.6.0-alpha01")
+    docs("androidx.test.espresso.idling:idling-net:3.6.0-alpha01")
+    docs("androidx.test.ext:junit:1.2.0-alpha01")
+    docs("androidx.test.ext:junit-ktx:1.2.0-alpha01")
+    docs("androidx.test.ext:truth:1.6.0-alpha01")
+    docs("androidx.test.services:storage:1.5.0-alpha01")
     docs("androidx.test.uiautomator:uiautomator:2.3.0-alpha02")
     docs("androidx.textclassifier:textclassifier:1.0.0-alpha04")
     docs("androidx.tracing:tracing:1.2.0-beta03")
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index f99dae3..1b401fe 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -73,6 +73,7 @@
     samples(project(":compose:foundation:foundation-layout:foundation-layout-samples"))
     samples(project(":compose:foundation:foundation:foundation-samples"))
     docs(project(":compose:material3:material3"))
+    docs(project(":compose:material3:material3-adaptive"))
     samples(project(":compose:material3:material3:material3-samples"))
     docs(project(":compose:material3:material3-window-size-class"))
     samples(project(":compose:material3:material3-window-size-class:material3-window-size-class-samples"))
diff --git a/emoji2/emoji2-bundled/api/1.4.0-beta02.txt b/emoji2/emoji2-bundled/api/1.4.0-beta02.txt
new file mode 100644
index 0000000..8749c28
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/1.4.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.emoji2.bundled {
+
+  public class BundledEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public BundledEmojiCompatConfig(android.content.Context);
+  }
+
+}
+
diff --git a/emoji2/emoji2-bundled/api/public_plus_experimental_1.4.0-beta02.txt b/emoji2/emoji2-bundled/api/public_plus_experimental_1.4.0-beta02.txt
new file mode 100644
index 0000000..8749c28
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/public_plus_experimental_1.4.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.emoji2.bundled {
+
+  public class BundledEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public BundledEmojiCompatConfig(android.content.Context);
+  }
+
+}
+
diff --git a/emoji2/emoji2-bundled/api/res-1.4.0-beta02.txt b/emoji2/emoji2-bundled/api/res-1.4.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/res-1.4.0-beta02.txt
diff --git a/emoji2/emoji2-bundled/api/restricted_1.4.0-beta02.txt b/emoji2/emoji2-bundled/api/restricted_1.4.0-beta02.txt
new file mode 100644
index 0000000..8749c28
--- /dev/null
+++ b/emoji2/emoji2-bundled/api/restricted_1.4.0-beta02.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.emoji2.bundled {
+
+  public class BundledEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public BundledEmojiCompatConfig(android.content.Context);
+  }
+
+}
+
diff --git a/emoji2/emoji2-emojipicker/api/1.4.0-beta02.txt b/emoji2/emoji2-emojipicker/api/1.4.0-beta02.txt
new file mode 100644
index 0000000..e2360fa
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/1.4.0-beta02.txt
@@ -0,0 +1,43 @@
+// Signature format: 4.0
+package androidx.emoji2.emojipicker {
+
+  public final class EmojiPickerView extends android.widget.FrameLayout {
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs);
+    ctor public EmojiPickerView(android.content.Context context);
+    method public int getEmojiGridColumns();
+    method public float getEmojiGridRows();
+    method public void setEmojiGridColumns(int);
+    method public void setEmojiGridRows(float);
+    method public void setOnEmojiPickedListener(androidx.core.util.Consumer<androidx.emoji2.emojipicker.EmojiViewItem>? onEmojiPickedListener);
+    method public void setRecentEmojiProvider(androidx.emoji2.emojipicker.RecentEmojiProvider recentEmojiProvider);
+    property public final int emojiGridColumns;
+    property public final float emojiGridRows;
+  }
+
+  public final class EmojiViewItem {
+    ctor public EmojiViewItem(String emoji, java.util.List<java.lang.String> variants);
+    method public String getEmoji();
+    method public java.util.List<java.lang.String> getVariants();
+    property public final String emoji;
+    property public final java.util.List<java.lang.String> variants;
+  }
+
+  public interface RecentEmojiAsyncProvider {
+    method public com.google.common.util.concurrent.ListenableFuture<java.util.List<java.lang.String>> getRecentEmojiListAsync();
+    method public void recordSelection(String emoji);
+  }
+
+  public interface RecentEmojiProvider {
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+  public final class RecentEmojiProviderAdapter implements androidx.emoji2.emojipicker.RecentEmojiProvider {
+    ctor public RecentEmojiProviderAdapter(androidx.emoji2.emojipicker.RecentEmojiAsyncProvider recentEmojiAsyncProvider);
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+}
+
diff --git a/emoji2/emoji2-emojipicker/api/public_plus_experimental_1.4.0-beta02.txt b/emoji2/emoji2-emojipicker/api/public_plus_experimental_1.4.0-beta02.txt
new file mode 100644
index 0000000..e2360fa
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/public_plus_experimental_1.4.0-beta02.txt
@@ -0,0 +1,43 @@
+// Signature format: 4.0
+package androidx.emoji2.emojipicker {
+
+  public final class EmojiPickerView extends android.widget.FrameLayout {
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs);
+    ctor public EmojiPickerView(android.content.Context context);
+    method public int getEmojiGridColumns();
+    method public float getEmojiGridRows();
+    method public void setEmojiGridColumns(int);
+    method public void setEmojiGridRows(float);
+    method public void setOnEmojiPickedListener(androidx.core.util.Consumer<androidx.emoji2.emojipicker.EmojiViewItem>? onEmojiPickedListener);
+    method public void setRecentEmojiProvider(androidx.emoji2.emojipicker.RecentEmojiProvider recentEmojiProvider);
+    property public final int emojiGridColumns;
+    property public final float emojiGridRows;
+  }
+
+  public final class EmojiViewItem {
+    ctor public EmojiViewItem(String emoji, java.util.List<java.lang.String> variants);
+    method public String getEmoji();
+    method public java.util.List<java.lang.String> getVariants();
+    property public final String emoji;
+    property public final java.util.List<java.lang.String> variants;
+  }
+
+  public interface RecentEmojiAsyncProvider {
+    method public com.google.common.util.concurrent.ListenableFuture<java.util.List<java.lang.String>> getRecentEmojiListAsync();
+    method public void recordSelection(String emoji);
+  }
+
+  public interface RecentEmojiProvider {
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+  public final class RecentEmojiProviderAdapter implements androidx.emoji2.emojipicker.RecentEmojiProvider {
+    ctor public RecentEmojiProviderAdapter(androidx.emoji2.emojipicker.RecentEmojiAsyncProvider recentEmojiAsyncProvider);
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+}
+
diff --git a/emoji2/emoji2-emojipicker/api/res-1.4.0-beta02.txt b/emoji2/emoji2-emojipicker/api/res-1.4.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/res-1.4.0-beta02.txt
diff --git a/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta02.txt b/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta02.txt
new file mode 100644
index 0000000..e2360fa
--- /dev/null
+++ b/emoji2/emoji2-emojipicker/api/restricted_1.4.0-beta02.txt
@@ -0,0 +1,43 @@
+// Signature format: 4.0
+package androidx.emoji2.emojipicker {
+
+  public final class EmojiPickerView extends android.widget.FrameLayout {
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public EmojiPickerView(android.content.Context context, optional android.util.AttributeSet? attrs);
+    ctor public EmojiPickerView(android.content.Context context);
+    method public int getEmojiGridColumns();
+    method public float getEmojiGridRows();
+    method public void setEmojiGridColumns(int);
+    method public void setEmojiGridRows(float);
+    method public void setOnEmojiPickedListener(androidx.core.util.Consumer<androidx.emoji2.emojipicker.EmojiViewItem>? onEmojiPickedListener);
+    method public void setRecentEmojiProvider(androidx.emoji2.emojipicker.RecentEmojiProvider recentEmojiProvider);
+    property public final int emojiGridColumns;
+    property public final float emojiGridRows;
+  }
+
+  public final class EmojiViewItem {
+    ctor public EmojiViewItem(String emoji, java.util.List<java.lang.String> variants);
+    method public String getEmoji();
+    method public java.util.List<java.lang.String> getVariants();
+    property public final String emoji;
+    property public final java.util.List<java.lang.String> variants;
+  }
+
+  public interface RecentEmojiAsyncProvider {
+    method public com.google.common.util.concurrent.ListenableFuture<java.util.List<java.lang.String>> getRecentEmojiListAsync();
+    method public void recordSelection(String emoji);
+  }
+
+  public interface RecentEmojiProvider {
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+  public final class RecentEmojiProviderAdapter implements androidx.emoji2.emojipicker.RecentEmojiProvider {
+    ctor public RecentEmojiProviderAdapter(androidx.emoji2.emojipicker.RecentEmojiAsyncProvider recentEmojiAsyncProvider);
+    method public suspend Object? getRecentEmojiList(kotlin.coroutines.Continuation<? super java.util.List<? extends java.lang.String>>);
+    method public void recordSelection(String emoji);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views-helper/api/1.4.0-beta02.txt b/emoji2/emoji2-views-helper/api/1.4.0-beta02.txt
new file mode 100644
index 0000000..30a6feb
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/1.4.0-beta02.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.emoji2.viewsintegration {
+
+  public final class EmojiEditTextHelper {
+    ctor public EmojiEditTextHelper(android.widget.EditText);
+    ctor public EmojiEditTextHelper(android.widget.EditText, boolean);
+    method public android.text.method.KeyListener? getKeyListener(android.text.method.KeyListener?);
+    method public int getMaxEmojiCount();
+    method public boolean isEnabled();
+    method public android.view.inputmethod.InputConnection? onCreateInputConnection(android.view.inputmethod.InputConnection?, android.view.inputmethod.EditorInfo);
+    method public void setEnabled(boolean);
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public final class EmojiTextViewHelper {
+    ctor public EmojiTextViewHelper(android.widget.TextView);
+    ctor public EmojiTextViewHelper(android.widget.TextView, boolean);
+    method public android.text.InputFilter![] getFilters(android.text.InputFilter![]);
+    method public boolean isEnabled();
+    method public void setAllCaps(boolean);
+    method public void setEnabled(boolean);
+    method public void updateTransformationMethod();
+    method public android.text.method.TransformationMethod? wrapTransformationMethod(android.text.method.TransformationMethod?);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views-helper/api/public_plus_experimental_1.4.0-beta02.txt b/emoji2/emoji2-views-helper/api/public_plus_experimental_1.4.0-beta02.txt
new file mode 100644
index 0000000..30a6feb
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/public_plus_experimental_1.4.0-beta02.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.emoji2.viewsintegration {
+
+  public final class EmojiEditTextHelper {
+    ctor public EmojiEditTextHelper(android.widget.EditText);
+    ctor public EmojiEditTextHelper(android.widget.EditText, boolean);
+    method public android.text.method.KeyListener? getKeyListener(android.text.method.KeyListener?);
+    method public int getMaxEmojiCount();
+    method public boolean isEnabled();
+    method public android.view.inputmethod.InputConnection? onCreateInputConnection(android.view.inputmethod.InputConnection?, android.view.inputmethod.EditorInfo);
+    method public void setEnabled(boolean);
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public final class EmojiTextViewHelper {
+    ctor public EmojiTextViewHelper(android.widget.TextView);
+    ctor public EmojiTextViewHelper(android.widget.TextView, boolean);
+    method public android.text.InputFilter![] getFilters(android.text.InputFilter![]);
+    method public boolean isEnabled();
+    method public void setAllCaps(boolean);
+    method public void setEnabled(boolean);
+    method public void updateTransformationMethod();
+    method public android.text.method.TransformationMethod? wrapTransformationMethod(android.text.method.TransformationMethod?);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views-helper/api/res-1.4.0-beta02.txt b/emoji2/emoji2-views-helper/api/res-1.4.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/res-1.4.0-beta02.txt
diff --git a/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta02.txt b/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta02.txt
new file mode 100644
index 0000000..30a6feb
--- /dev/null
+++ b/emoji2/emoji2-views-helper/api/restricted_1.4.0-beta02.txt
@@ -0,0 +1,27 @@
+// Signature format: 4.0
+package androidx.emoji2.viewsintegration {
+
+  public final class EmojiEditTextHelper {
+    ctor public EmojiEditTextHelper(android.widget.EditText);
+    ctor public EmojiEditTextHelper(android.widget.EditText, boolean);
+    method public android.text.method.KeyListener? getKeyListener(android.text.method.KeyListener?);
+    method public int getMaxEmojiCount();
+    method public boolean isEnabled();
+    method public android.view.inputmethod.InputConnection? onCreateInputConnection(android.view.inputmethod.InputConnection?, android.view.inputmethod.EditorInfo);
+    method public void setEnabled(boolean);
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public final class EmojiTextViewHelper {
+    ctor public EmojiTextViewHelper(android.widget.TextView);
+    ctor public EmojiTextViewHelper(android.widget.TextView, boolean);
+    method public android.text.InputFilter![] getFilters(android.text.InputFilter![]);
+    method public boolean isEnabled();
+    method public void setAllCaps(boolean);
+    method public void setEnabled(boolean);
+    method public void updateTransformationMethod();
+    method public android.text.method.TransformationMethod? wrapTransformationMethod(android.text.method.TransformationMethod?);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views/api/1.4.0-beta02.txt b/emoji2/emoji2-views/api/1.4.0-beta02.txt
new file mode 100644
index 0000000..879b30e
--- /dev/null
+++ b/emoji2/emoji2-views/api/1.4.0-beta02.txt
@@ -0,0 +1,34 @@
+// Signature format: 4.0
+package androidx.emoji2.widget {
+
+  public class EmojiButton extends android.widget.Button {
+    ctor public EmojiButton(android.content.Context);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class EmojiEditText extends android.widget.EditText {
+    ctor public EmojiEditText(android.content.Context);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?, int);
+    method public int getMaxEmojiCount();
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public class EmojiExtractTextLayout extends android.widget.LinearLayout {
+    ctor public EmojiExtractTextLayout(android.content.Context);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?, int);
+    method public int getEmojiReplaceStrategy();
+    method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
+    method public void setEmojiReplaceStrategy(int);
+  }
+
+  public class EmojiTextView extends android.widget.TextView {
+    ctor public EmojiTextView(android.content.Context);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views/api/public_plus_experimental_1.4.0-beta02.txt b/emoji2/emoji2-views/api/public_plus_experimental_1.4.0-beta02.txt
new file mode 100644
index 0000000..879b30e
--- /dev/null
+++ b/emoji2/emoji2-views/api/public_plus_experimental_1.4.0-beta02.txt
@@ -0,0 +1,34 @@
+// Signature format: 4.0
+package androidx.emoji2.widget {
+
+  public class EmojiButton extends android.widget.Button {
+    ctor public EmojiButton(android.content.Context);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class EmojiEditText extends android.widget.EditText {
+    ctor public EmojiEditText(android.content.Context);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?, int);
+    method public int getMaxEmojiCount();
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public class EmojiExtractTextLayout extends android.widget.LinearLayout {
+    ctor public EmojiExtractTextLayout(android.content.Context);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?, int);
+    method public int getEmojiReplaceStrategy();
+    method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
+    method public void setEmojiReplaceStrategy(int);
+  }
+
+  public class EmojiTextView extends android.widget.TextView {
+    ctor public EmojiTextView(android.content.Context);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+}
+
diff --git a/emoji2/emoji2-views/api/res-1.4.0-beta02.txt b/emoji2/emoji2-views/api/res-1.4.0-beta02.txt
new file mode 100644
index 0000000..8bc8423
--- /dev/null
+++ b/emoji2/emoji2-views/api/res-1.4.0-beta02.txt
@@ -0,0 +1,2 @@
+attr emojiReplaceStrategy
+attr maxEmojiCount
diff --git a/emoji2/emoji2-views/api/restricted_1.4.0-beta02.txt b/emoji2/emoji2-views/api/restricted_1.4.0-beta02.txt
new file mode 100644
index 0000000..879b30e
--- /dev/null
+++ b/emoji2/emoji2-views/api/restricted_1.4.0-beta02.txt
@@ -0,0 +1,34 @@
+// Signature format: 4.0
+package androidx.emoji2.widget {
+
+  public class EmojiButton extends android.widget.Button {
+    ctor public EmojiButton(android.content.Context);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiButton(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class EmojiEditText extends android.widget.EditText {
+    ctor public EmojiEditText(android.content.Context);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet?, int);
+    method public int getMaxEmojiCount();
+    method public void setMaxEmojiCount(@IntRange(from=0) int);
+  }
+
+  public class EmojiExtractTextLayout extends android.widget.LinearLayout {
+    ctor public EmojiExtractTextLayout(android.content.Context);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet?, int);
+    method public int getEmojiReplaceStrategy();
+    method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
+    method public void setEmojiReplaceStrategy(int);
+  }
+
+  public class EmojiTextView extends android.widget.TextView {
+    ctor public EmojiTextView(android.content.Context);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?);
+    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+}
+
diff --git a/emoji2/emoji2/api/1.4.0-beta02.txt b/emoji2/emoji2/api/1.4.0-beta02.txt
new file mode 100644
index 0000000..11d9335
--- /dev/null
+++ b/emoji2/emoji2/api/1.4.0-beta02.txt
@@ -0,0 +1,131 @@
+// Signature format: 4.0
+package androidx.emoji2.text {
+
+  public final class DefaultEmojiCompatConfig {
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
+  }
+
+  @AnyThread public class EmojiCompat {
+    method public static androidx.emoji2.text.EmojiCompat get();
+    method public String getAssetSignature();
+    method public int getEmojiEnd(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiMatch(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiStart(CharSequence, @IntRange(from=0) int);
+    method public int getLoadState();
+    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, @IntRange(from=0) int, @IntRange(from=0) int, boolean);
+    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence, @IntRange(from=0) int);
+    method public static androidx.emoji2.text.EmojiCompat? init(android.content.Context);
+    method public static androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config);
+    method public static boolean isConfigured();
+    method public void load();
+    method @CheckResult public CharSequence? process(CharSequence?);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, int);
+    method public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void updateEditorInfo(android.view.inputmethod.EditorInfo);
+    field public static final String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+    field public static final String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+    field public static final int EMOJI_FALLBACK = 2; // 0x2
+    field public static final int EMOJI_SUPPORTED = 1; // 0x1
+    field public static final int EMOJI_UNSUPPORTED = 0; // 0x0
+    field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
+    field public static final int LOAD_STATE_FAILED = 2; // 0x2
+    field public static final int LOAD_STATE_LOADING = 0; // 0x0
+    field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+    field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
+  }
+
+  public abstract static class EmojiCompat.Config {
+    ctor protected EmojiCompat.Config(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader);
+    method protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
+    method public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(@ColorInt int);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker);
+    method public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int);
+    method public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer!>?);
+    method public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+  }
+
+  public static interface EmojiCompat.GlyphChecker {
+    method public boolean hasGlyph(CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+  }
+
+  public abstract static class EmojiCompat.InitCallback {
+    ctor public EmojiCompat.InitCallback();
+    method public void onFailed(Throwable?);
+    method public void onInitialized();
+  }
+
+  public static interface EmojiCompat.MetadataRepoLoader {
+    method public void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback);
+  }
+
+  public abstract static class EmojiCompat.MetadataRepoLoaderCallback {
+    ctor public EmojiCompat.MetadataRepoLoaderCallback();
+    method public abstract void onFailed(Throwable?);
+    method public abstract void onLoaded(androidx.emoji2.text.MetadataRepo);
+  }
+
+  public static interface EmojiCompat.SpanFactory {
+    method @RequiresApi(19) public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer);
+  }
+
+  public class EmojiCompatInitializer implements androidx.startup.Initializer<java.lang.Boolean> {
+    ctor public EmojiCompatInitializer();
+    method public Boolean create(android.content.Context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+  }
+
+  @RequiresApi(19) public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+    method public int getSize(android.graphics.Paint, CharSequence!, int, int, android.graphics.Paint.FontMetricsInt?);
+    method public final androidx.emoji2.text.TypefaceEmojiRasterizer getTypefaceRasterizer();
+  }
+
+  public class FontRequestEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
+    method @Deprecated public androidx.emoji2.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler?);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setLoadingExecutor(java.util.concurrent.Executor);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy?);
+  }
+
+  public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
+    method public long getRetryDelay();
+  }
+
+  public abstract static class FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.RetryPolicy();
+    method public abstract long getRetryDelay();
+  }
+
+  @AnyThread @RequiresApi(19) public final class MetadataRepo {
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.content.res.AssetManager, String) throws java.io.IOException;
+  }
+
+  @AnyThread @RequiresApi(19) public class TypefaceEmojiRasterizer {
+    method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+    method public int getCodepointAt(int);
+    method public int getCodepointsLength();
+    method public int getHeight();
+    method public android.graphics.Typeface getTypeface();
+    method public int getWidth();
+    method public boolean isDefaultEmoji();
+    method public boolean isPreferredSystemRender();
+  }
+
+}
+
diff --git a/emoji2/emoji2/api/public_plus_experimental_1.4.0-beta02.txt b/emoji2/emoji2/api/public_plus_experimental_1.4.0-beta02.txt
new file mode 100644
index 0000000..11d9335
--- /dev/null
+++ b/emoji2/emoji2/api/public_plus_experimental_1.4.0-beta02.txt
@@ -0,0 +1,131 @@
+// Signature format: 4.0
+package androidx.emoji2.text {
+
+  public final class DefaultEmojiCompatConfig {
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
+  }
+
+  @AnyThread public class EmojiCompat {
+    method public static androidx.emoji2.text.EmojiCompat get();
+    method public String getAssetSignature();
+    method public int getEmojiEnd(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiMatch(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiStart(CharSequence, @IntRange(from=0) int);
+    method public int getLoadState();
+    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, @IntRange(from=0) int, @IntRange(from=0) int, boolean);
+    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence, @IntRange(from=0) int);
+    method public static androidx.emoji2.text.EmojiCompat? init(android.content.Context);
+    method public static androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config);
+    method public static boolean isConfigured();
+    method public void load();
+    method @CheckResult public CharSequence? process(CharSequence?);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, int);
+    method public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void updateEditorInfo(android.view.inputmethod.EditorInfo);
+    field public static final String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+    field public static final String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+    field public static final int EMOJI_FALLBACK = 2; // 0x2
+    field public static final int EMOJI_SUPPORTED = 1; // 0x1
+    field public static final int EMOJI_UNSUPPORTED = 0; // 0x0
+    field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
+    field public static final int LOAD_STATE_FAILED = 2; // 0x2
+    field public static final int LOAD_STATE_LOADING = 0; // 0x0
+    field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+    field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
+  }
+
+  public abstract static class EmojiCompat.Config {
+    ctor protected EmojiCompat.Config(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader);
+    method protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
+    method public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(@ColorInt int);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker);
+    method public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int);
+    method public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer!>?);
+    method public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+  }
+
+  public static interface EmojiCompat.GlyphChecker {
+    method public boolean hasGlyph(CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+  }
+
+  public abstract static class EmojiCompat.InitCallback {
+    ctor public EmojiCompat.InitCallback();
+    method public void onFailed(Throwable?);
+    method public void onInitialized();
+  }
+
+  public static interface EmojiCompat.MetadataRepoLoader {
+    method public void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback);
+  }
+
+  public abstract static class EmojiCompat.MetadataRepoLoaderCallback {
+    ctor public EmojiCompat.MetadataRepoLoaderCallback();
+    method public abstract void onFailed(Throwable?);
+    method public abstract void onLoaded(androidx.emoji2.text.MetadataRepo);
+  }
+
+  public static interface EmojiCompat.SpanFactory {
+    method @RequiresApi(19) public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer);
+  }
+
+  public class EmojiCompatInitializer implements androidx.startup.Initializer<java.lang.Boolean> {
+    ctor public EmojiCompatInitializer();
+    method public Boolean create(android.content.Context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+  }
+
+  @RequiresApi(19) public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+    method public int getSize(android.graphics.Paint, CharSequence!, int, int, android.graphics.Paint.FontMetricsInt?);
+    method public final androidx.emoji2.text.TypefaceEmojiRasterizer getTypefaceRasterizer();
+  }
+
+  public class FontRequestEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
+    method @Deprecated public androidx.emoji2.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler?);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setLoadingExecutor(java.util.concurrent.Executor);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy?);
+  }
+
+  public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
+    method public long getRetryDelay();
+  }
+
+  public abstract static class FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.RetryPolicy();
+    method public abstract long getRetryDelay();
+  }
+
+  @AnyThread @RequiresApi(19) public final class MetadataRepo {
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.content.res.AssetManager, String) throws java.io.IOException;
+  }
+
+  @AnyThread @RequiresApi(19) public class TypefaceEmojiRasterizer {
+    method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+    method public int getCodepointAt(int);
+    method public int getCodepointsLength();
+    method public int getHeight();
+    method public android.graphics.Typeface getTypeface();
+    method public int getWidth();
+    method public boolean isDefaultEmoji();
+    method public boolean isPreferredSystemRender();
+  }
+
+}
+
diff --git a/emoji2/emoji2/api/res-1.4.0-beta02.txt b/emoji2/emoji2/api/res-1.4.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emoji2/emoji2/api/res-1.4.0-beta02.txt
diff --git a/emoji2/emoji2/api/restricted_1.4.0-beta02.txt b/emoji2/emoji2/api/restricted_1.4.0-beta02.txt
new file mode 100644
index 0000000..11d9335
--- /dev/null
+++ b/emoji2/emoji2/api/restricted_1.4.0-beta02.txt
@@ -0,0 +1,131 @@
+// Signature format: 4.0
+package androidx.emoji2.text {
+
+  public final class DefaultEmojiCompatConfig {
+    method public static androidx.emoji2.text.FontRequestEmojiCompatConfig? create(android.content.Context);
+  }
+
+  @AnyThread public class EmojiCompat {
+    method public static androidx.emoji2.text.EmojiCompat get();
+    method public String getAssetSignature();
+    method public int getEmojiEnd(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiMatch(CharSequence, @IntRange(from=0) int);
+    method public int getEmojiStart(CharSequence, @IntRange(from=0) int);
+    method public int getLoadState();
+    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, @IntRange(from=0) int, @IntRange(from=0) int, boolean);
+    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence);
+    method @Deprecated public boolean hasEmojiGlyph(CharSequence, @IntRange(from=0) int);
+    method public static androidx.emoji2.text.EmojiCompat? init(android.content.Context);
+    method public static androidx.emoji2.text.EmojiCompat init(androidx.emoji2.text.EmojiCompat.Config);
+    method public static boolean isConfigured();
+    method public void load();
+    method @CheckResult public CharSequence? process(CharSequence?);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @CheckResult public CharSequence? process(CharSequence?, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, int);
+    method public void registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public void updateEditorInfo(android.view.inputmethod.EditorInfo);
+    field public static final String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
+    field public static final String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+    field public static final int EMOJI_FALLBACK = 2; // 0x2
+    field public static final int EMOJI_SUPPORTED = 1; // 0x1
+    field public static final int EMOJI_UNSUPPORTED = 0; // 0x0
+    field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
+    field public static final int LOAD_STATE_FAILED = 2; // 0x2
+    field public static final int LOAD_STATE_LOADING = 0; // 0x0
+    field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+    field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
+    field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
+  }
+
+  public abstract static class EmojiCompat.Config {
+    ctor protected EmojiCompat.Config(androidx.emoji2.text.EmojiCompat.MetadataRepoLoader);
+    method protected final androidx.emoji2.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
+    method public androidx.emoji2.text.EmojiCompat.Config registerInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorColor(@ColorInt int);
+    method public androidx.emoji2.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setGlyphChecker(androidx.emoji2.text.EmojiCompat.GlyphChecker);
+    method public androidx.emoji2.text.EmojiCompat.Config setMetadataLoadStrategy(int);
+    method public androidx.emoji2.text.EmojiCompat.Config setReplaceAll(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setSpanFactory(androidx.emoji2.text.EmojiCompat.SpanFactory);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
+    method public androidx.emoji2.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer!>?);
+    method public androidx.emoji2.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji2.text.EmojiCompat.InitCallback);
+  }
+
+  public static interface EmojiCompat.GlyphChecker {
+    method public boolean hasGlyph(CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+  }
+
+  public abstract static class EmojiCompat.InitCallback {
+    ctor public EmojiCompat.InitCallback();
+    method public void onFailed(Throwable?);
+    method public void onInitialized();
+  }
+
+  public static interface EmojiCompat.MetadataRepoLoader {
+    method public void load(androidx.emoji2.text.EmojiCompat.MetadataRepoLoaderCallback);
+  }
+
+  public abstract static class EmojiCompat.MetadataRepoLoaderCallback {
+    ctor public EmojiCompat.MetadataRepoLoaderCallback();
+    method public abstract void onFailed(Throwable?);
+    method public abstract void onLoaded(androidx.emoji2.text.MetadataRepo);
+  }
+
+  public static interface EmojiCompat.SpanFactory {
+    method @RequiresApi(19) public androidx.emoji2.text.EmojiSpan createSpan(androidx.emoji2.text.TypefaceEmojiRasterizer);
+  }
+
+  public class EmojiCompatInitializer implements androidx.startup.Initializer<java.lang.Boolean> {
+    ctor public EmojiCompatInitializer();
+    method public Boolean create(android.content.Context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>!> dependencies();
+  }
+
+  @RequiresApi(19) public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
+    method public int getSize(android.graphics.Paint, CharSequence!, int, int, android.graphics.Paint.FontMetricsInt?);
+    method public final androidx.emoji2.text.TypefaceEmojiRasterizer getTypefaceRasterizer();
+  }
+
+  public class FontRequestEmojiCompatConfig extends androidx.emoji2.text.EmojiCompat.Config {
+    ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
+    method @Deprecated public androidx.emoji2.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler?);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setLoadingExecutor(java.util.concurrent.Executor);
+    method public androidx.emoji2.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy?);
+  }
+
+  public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji2.text.FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
+    method public long getRetryDelay();
+  }
+
+  public abstract static class FontRequestEmojiCompatConfig.RetryPolicy {
+    ctor public FontRequestEmojiCompatConfig.RetryPolicy();
+    method public abstract long getRetryDelay();
+  }
+
+  @AnyThread @RequiresApi(19) public final class MetadataRepo {
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
+    method public static androidx.emoji2.text.MetadataRepo create(android.content.res.AssetManager, String) throws java.io.IOException;
+  }
+
+  @AnyThread @RequiresApi(19) public class TypefaceEmojiRasterizer {
+    method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+    method public int getCodepointAt(int);
+    method public int getCodepointsLength();
+    method public int getHeight();
+    method public android.graphics.Typeface getTypeface();
+    method public int getWidth();
+    method public boolean isDefaultEmoji();
+    method public boolean isPreferredSystemRender();
+  }
+
+}
+
diff --git a/external/paparazzi/paparazzi/build.gradle b/external/paparazzi/paparazzi/build.gradle
index dcc5194..8e87582 100644
--- a/external/paparazzi/paparazzi/build.gradle
+++ b/external/paparazzi/paparazzi/build.gradle
@@ -1,7 +1,6 @@
 import androidx.build.LibraryType
 import org.gradle.api.artifacts.transform.TransformParameters.None
 import java.util.zip.ZipInputStream
-import org.gradle.api.attributes.java.TargetJvmEnvironment
 
 plugins {
     id("AndroidXPlugin")
diff --git a/fragment/fragment-ktx/api/1.6.0-beta01.txt b/fragment/fragment-ktx/api/1.6.0-beta01.txt
new file mode 100644
index 0000000..b93e06b
--- /dev/null
+++ b/fragment/fragment-ktx/api/1.6.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @MainThread public static inline void commitNow(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, optional boolean now, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, String tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-ktx/api/public_plus_experimental_1.6.0-beta01.txt b/fragment/fragment-ktx/api/public_plus_experimental_1.6.0-beta01.txt
new file mode 100644
index 0000000..b93e06b
--- /dev/null
+++ b/fragment/fragment-ktx/api/public_plus_experimental_1.6.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @MainThread public static inline void commitNow(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, optional boolean now, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, String tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-ktx/api/res-1.6.0-beta01.txt b/fragment/fragment-ktx/api/res-1.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-ktx/api/res-1.6.0-beta01.txt
diff --git a/fragment/fragment-ktx/api/restricted_1.6.0-beta01.txt b/fragment/fragment-ktx/api/restricted_1.6.0-beta01.txt
new file mode 100644
index 0000000..b93e06b
--- /dev/null
+++ b/fragment/fragment-ktx/api/restricted_1.6.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @MainThread public static inline void commitNow(androidx.fragment.app.FragmentManager, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, optional boolean now, optional boolean allowStateLoss, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.FragmentTransaction, String tag, optional android.os.Bundle? args);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, optional String? tag, optional android.os.Bundle? args);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> activityViewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras> extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> viewModels(androidx.fragment.app.Fragment, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-testing-manifest/api/1.6.0-beta01.txt b/fragment/fragment-testing-manifest/api/1.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/fragment/fragment-testing-manifest/api/1.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/fragment/fragment-testing-manifest/api/public_plus_experimental_1.6.0-beta01.txt b/fragment/fragment-testing-manifest/api/public_plus_experimental_1.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/fragment/fragment-testing-manifest/api/public_plus_experimental_1.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/fragment/fragment-testing-manifest/api/res-1.6.0-beta01.txt b/fragment/fragment-testing-manifest/api/res-1.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-testing-manifest/api/res-1.6.0-beta01.txt
diff --git a/fragment/fragment-testing-manifest/api/restricted_1.6.0-beta01.txt b/fragment/fragment-testing-manifest/api/restricted_1.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/fragment/fragment-testing-manifest/api/restricted_1.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/fragment/fragment-testing/api/1.6.0-beta01.txt b/fragment/fragment-testing/api/1.6.0-beta01.txt
new file mode 100644
index 0000000..d5c260e
--- /dev/null
+++ b/fragment/fragment-testing/api/1.6.0-beta01.txt
@@ -0,0 +1,60 @@
+// Signature format: 4.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> implements java.io.Closeable {
+    method public void close();
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+    method public androidx.fragment.app.testing.FragmentScenario<F> moveToState(androidx.lifecycle.Lifecycle.State newState);
+    method public androidx.fragment.app.testing.FragmentScenario<F> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F> action);
+    method public androidx.fragment.app.testing.FragmentScenario<F> recreate();
+    field public static final androidx.fragment.app.testing.FragmentScenario.Companion Companion;
+  }
+
+  public static final class FragmentScenario.Companion {
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+  }
+
+  public static fun interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F fragment);
+  }
+
+  public final class FragmentScenarioKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/api/public_plus_experimental_1.6.0-beta01.txt b/fragment/fragment-testing/api/public_plus_experimental_1.6.0-beta01.txt
new file mode 100644
index 0000000..d5c260e
--- /dev/null
+++ b/fragment/fragment-testing/api/public_plus_experimental_1.6.0-beta01.txt
@@ -0,0 +1,60 @@
+// Signature format: 4.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> implements java.io.Closeable {
+    method public void close();
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+    method public androidx.fragment.app.testing.FragmentScenario<F> moveToState(androidx.lifecycle.Lifecycle.State newState);
+    method public androidx.fragment.app.testing.FragmentScenario<F> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F> action);
+    method public androidx.fragment.app.testing.FragmentScenario<F> recreate();
+    field public static final androidx.fragment.app.testing.FragmentScenario.Companion Companion;
+  }
+
+  public static final class FragmentScenario.Companion {
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+  }
+
+  public static fun interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F fragment);
+  }
+
+  public final class FragmentScenarioKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/api/res-1.6.0-beta01.txt b/fragment/fragment-testing/api/res-1.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-testing/api/res-1.6.0-beta01.txt
diff --git a/fragment/fragment-testing/api/restricted_1.6.0-beta01.txt b/fragment/fragment-testing/api/restricted_1.6.0-beta01.txt
new file mode 100644
index 0000000..d5c260e
--- /dev/null
+++ b/fragment/fragment-testing/api/restricted_1.6.0-beta01.txt
@@ -0,0 +1,60 @@
+// Signature format: 4.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> implements java.io.Closeable {
+    method public void close();
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+    method public androidx.fragment.app.testing.FragmentScenario<F> moveToState(androidx.lifecycle.Lifecycle.State newState);
+    method public androidx.fragment.app.testing.FragmentScenario<F> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F> action);
+    method public androidx.fragment.app.testing.FragmentScenario<F> recreate();
+    field public static final androidx.fragment.app.testing.FragmentScenario.Companion Companion;
+  }
+
+  public static final class FragmentScenario.Companion {
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launch(Class<F> fragmentClass);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, android.os.Bundle? fragmentArgs, @StyleRes int themeResId, androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass, optional android.os.Bundle? fragmentArgs);
+    method public <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchInContainer(Class<F> fragmentClass);
+  }
+
+  public static fun interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F fragment);
+  }
+
+  public final class FragmentScenarioKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragment(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.fragment.app.FragmentFactory? factory);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, optional androidx.fragment.app.FragmentFactory? factory);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F> launchFragmentInContainer(optional android.os.Bundle? fragmentArgs, optional @StyleRes int themeResId, optional androidx.lifecycle.Lifecycle.State initialState, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/build.gradle b/fragment/fragment-testing/build.gradle
index 7afdb67..4ef2ed4 100644
--- a/fragment/fragment-testing/build.gradle
+++ b/fragment/fragment-testing/build.gradle
@@ -25,7 +25,7 @@
 
 dependencies {
     api(project(":fragment:fragment-ktx"))
-    api(libs.testCore)
+    api("androidx.test:core:1.5.0")
     api(libs.kotlinStdlib)
     api(project(":fragment:fragment-testing-manifest"))
     androidTestImplementation(libs.kotlinStdlib)
diff --git a/fragment/fragment/api/1.6.0-beta01.txt b/fragment/fragment/api/1.6.0-beta01.txt
new file mode 100644
index 0000000..2f167cf
--- /dev/null
+++ b/fragment/fragment/api/1.6.0-beta01.txt
@@ -0,0 +1,554 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @Deprecated @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @Deprecated @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @Deprecated @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @Deprecated @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method @Deprecated public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.Intent, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.lifecycle.LifecycleOwner {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context context);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs);
+    method public <F extends androidx.fragment.app.Fragment> F! getFragment();
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method @Deprecated public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method @Deprecated public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method @Deprecated public void dispatchLowMemory();
+    method @Deprecated public void dispatchMultiWindowModeChanged(boolean);
+    method @Deprecated public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method @Deprecated public void dispatchPictureInPictureModeChanged(boolean);
+    method @Deprecated public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method @Deprecated public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method @Deprecated public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public void clearBackStack(String);
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @MainThread public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy? getStrictModePolicy();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method @MainThread public boolean popBackStackImmediate();
+    method @MainThread public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public void restoreBackStack(String);
+    method public void saveBackStack(String);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void setStrictModePolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy?);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public default void onBackStackChangeCommitted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public default void onBackStackChangeStarted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method @MainThread public abstract void commitNow();
+    method @MainThread public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
+package androidx.fragment.app.strictmode {
+
+  public final class FragmentReuseViolation extends androidx.fragment.app.strictmode.Violation {
+    method public String getPreviousFragmentId();
+    property public final String previousFragmentId;
+  }
+
+  public final class FragmentStrictMode {
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy getDefaultPolicy();
+    method @VisibleForTesting public void onPolicyViolation(androidx.fragment.app.strictmode.Violation violation);
+    method public void setDefaultPolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy);
+    property public final androidx.fragment.app.strictmode.FragmentStrictMode.Policy defaultPolicy;
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode INSTANCE;
+  }
+
+  public static fun interface FragmentStrictMode.OnViolationListener {
+    method public void onViolation(androidx.fragment.app.strictmode.Violation violation);
+  }
+
+  public static final class FragmentStrictMode.Policy {
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode.Policy LAX;
+  }
+
+  public static final class FragmentStrictMode.Policy.Builder {
+    ctor public FragmentStrictMode.Policy.Builder();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(Class<? extends androidx.fragment.app.Fragment> fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(String fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy build();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentReuse();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentTagUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectRetainInstanceUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectSetUserVisibleHint();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectTargetFragmentUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongFragmentContainer();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongNestedHierarchy();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyDeath();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyListener(androidx.fragment.app.strictmode.FragmentStrictMode.OnViolationListener listener);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyLog();
+  }
+
+  public final class FragmentTagUsageViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup? getParentContainer();
+    property public final android.view.ViewGroup? parentContainer;
+  }
+
+  public final class GetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class GetTargetFragmentRequestCodeUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public final class GetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public abstract class RetainInstanceUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public final class SetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class SetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+    method public int getRequestCode();
+    method public androidx.fragment.app.Fragment getTargetFragment();
+    property public final int requestCode;
+    property public final androidx.fragment.app.Fragment targetFragment;
+  }
+
+  public final class SetUserVisibleHintViolation extends androidx.fragment.app.strictmode.Violation {
+    method public boolean isVisibleToUser();
+    property public final boolean isVisibleToUser;
+  }
+
+  public abstract class TargetFragmentUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public abstract class Violation extends java.lang.RuntimeException {
+    method public final androidx.fragment.app.Fragment getFragment();
+    property public final androidx.fragment.app.Fragment fragment;
+  }
+
+  public final class WrongFragmentContainerViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup getContainer();
+    property public final android.view.ViewGroup container;
+  }
+
+  public final class WrongNestedHierarchyViolation extends androidx.fragment.app.strictmode.Violation {
+    method public int getContainerId();
+    method public androidx.fragment.app.Fragment getExpectedParentFragment();
+    property public final int containerId;
+    property public final androidx.fragment.app.Fragment expectedParentFragment;
+  }
+
+}
+
diff --git a/fragment/fragment/api/public_plus_experimental_1.6.0-beta01.txt b/fragment/fragment/api/public_plus_experimental_1.6.0-beta01.txt
new file mode 100644
index 0000000..2f167cf
--- /dev/null
+++ b/fragment/fragment/api/public_plus_experimental_1.6.0-beta01.txt
@@ -0,0 +1,554 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @Deprecated @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @Deprecated @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @Deprecated @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @Deprecated @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method @Deprecated public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.Intent, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.lifecycle.LifecycleOwner {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context context);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs);
+    method public <F extends androidx.fragment.app.Fragment> F! getFragment();
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method @Deprecated public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method @Deprecated public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method @Deprecated public void dispatchLowMemory();
+    method @Deprecated public void dispatchMultiWindowModeChanged(boolean);
+    method @Deprecated public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method @Deprecated public void dispatchPictureInPictureModeChanged(boolean);
+    method @Deprecated public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method @Deprecated public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method @Deprecated public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public void clearBackStack(String);
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @MainThread public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy? getStrictModePolicy();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method @MainThread public boolean popBackStackImmediate();
+    method @MainThread public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public void restoreBackStack(String);
+    method public void saveBackStack(String);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void setStrictModePolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy?);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public default void onBackStackChangeCommitted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public default void onBackStackChangeStarted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method @MainThread public abstract void commitNow();
+    method @MainThread public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
+package androidx.fragment.app.strictmode {
+
+  public final class FragmentReuseViolation extends androidx.fragment.app.strictmode.Violation {
+    method public String getPreviousFragmentId();
+    property public final String previousFragmentId;
+  }
+
+  public final class FragmentStrictMode {
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy getDefaultPolicy();
+    method @VisibleForTesting public void onPolicyViolation(androidx.fragment.app.strictmode.Violation violation);
+    method public void setDefaultPolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy);
+    property public final androidx.fragment.app.strictmode.FragmentStrictMode.Policy defaultPolicy;
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode INSTANCE;
+  }
+
+  public static fun interface FragmentStrictMode.OnViolationListener {
+    method public void onViolation(androidx.fragment.app.strictmode.Violation violation);
+  }
+
+  public static final class FragmentStrictMode.Policy {
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode.Policy LAX;
+  }
+
+  public static final class FragmentStrictMode.Policy.Builder {
+    ctor public FragmentStrictMode.Policy.Builder();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(Class<? extends androidx.fragment.app.Fragment> fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(String fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy build();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentReuse();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentTagUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectRetainInstanceUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectSetUserVisibleHint();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectTargetFragmentUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongFragmentContainer();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongNestedHierarchy();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyDeath();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyListener(androidx.fragment.app.strictmode.FragmentStrictMode.OnViolationListener listener);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyLog();
+  }
+
+  public final class FragmentTagUsageViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup? getParentContainer();
+    property public final android.view.ViewGroup? parentContainer;
+  }
+
+  public final class GetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class GetTargetFragmentRequestCodeUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public final class GetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public abstract class RetainInstanceUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public final class SetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class SetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+    method public int getRequestCode();
+    method public androidx.fragment.app.Fragment getTargetFragment();
+    property public final int requestCode;
+    property public final androidx.fragment.app.Fragment targetFragment;
+  }
+
+  public final class SetUserVisibleHintViolation extends androidx.fragment.app.strictmode.Violation {
+    method public boolean isVisibleToUser();
+    property public final boolean isVisibleToUser;
+  }
+
+  public abstract class TargetFragmentUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public abstract class Violation extends java.lang.RuntimeException {
+    method public final androidx.fragment.app.Fragment getFragment();
+    property public final androidx.fragment.app.Fragment fragment;
+  }
+
+  public final class WrongFragmentContainerViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup getContainer();
+    property public final android.view.ViewGroup container;
+  }
+
+  public final class WrongNestedHierarchyViolation extends androidx.fragment.app.strictmode.Violation {
+    method public int getContainerId();
+    method public androidx.fragment.app.Fragment getExpectedParentFragment();
+    property public final int containerId;
+    property public final androidx.fragment.app.Fragment expectedParentFragment;
+  }
+
+}
+
diff --git a/fragment/fragment/api/res-1.6.0-beta01.txt b/fragment/fragment/api/res-1.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment/api/res-1.6.0-beta01.txt
diff --git a/fragment/fragment/api/restricted_1.6.0-beta01.txt b/fragment/fragment/api/restricted_1.6.0-beta01.txt
new file mode 100644
index 0000000..83801ad
--- /dev/null
+++ b/fragment/fragment/api/restricted_1.6.0-beta01.txt
@@ -0,0 +1,583 @@
+// Signature format: 4.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method @MainThread public void dismissNow();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setupDialog(android.app.Dialog, int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.view.LayoutInflater getLayoutInflater(android.os.Bundle?);
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean hasOptionsMenu();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean isMenuVisible();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @Deprecated @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @Deprecated @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @Deprecated @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @Deprecated @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method @Deprecated public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.Intent, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context context);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs, optional int defStyleAttr);
+    ctor public FragmentContainerView(android.content.Context context, android.util.AttributeSet? attrs);
+    method public <F extends androidx.fragment.app.Fragment> F! getFragment();
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method @Deprecated public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method @Deprecated public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method @Deprecated public void dispatchLowMemory();
+    method @Deprecated public void dispatchMultiWindowModeChanged(boolean);
+    method @Deprecated public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method @Deprecated public void dispatchPictureInPictureModeChanged(boolean);
+    method @Deprecated public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method @Deprecated public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method @Deprecated public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public void clearBackStack(String);
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @MainThread public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy? getStrictModePolicy();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.fragment.app.FragmentTransaction openTransaction();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method @MainThread public boolean popBackStackImmediate();
+    method @MainThread public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public void restoreBackStack(String);
+    method public void saveBackStack(String);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void setStrictModePolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy?);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public default void onBackStackChangeCommitted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public default void onBackStackChangeStarted(androidx.fragment.app.Fragment, boolean);
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method @MainThread public abstract void commitNow();
+    method @MainThread public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class FragmentTransitionImpl {
+    ctor public FragmentTransitionImpl();
+    method public abstract void addTarget(Object, android.view.View);
+    method public abstract void addTargets(Object, java.util.ArrayList<android.view.View!>);
+    method public abstract void beginDelayedTransition(android.view.ViewGroup, Object?);
+    method protected static void bfsAddViewChildren(java.util.List<android.view.View!>!, android.view.View!);
+    method public abstract boolean canHandle(Object);
+    method public abstract Object! cloneTransition(Object?);
+    method protected void getBoundsOnScreen(android.view.View!, android.graphics.Rect!);
+    method protected static boolean isNullOrEmpty(java.util.List!);
+    method public abstract Object! mergeTransitionsInSequence(Object?, Object?, Object?);
+    method public abstract Object! mergeTransitionsTogether(Object?, Object?, Object?);
+    method public abstract void removeTarget(Object, android.view.View);
+    method public abstract void replaceTargets(Object, java.util.ArrayList<android.view.View!>!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void scheduleHideFragmentView(Object, android.view.View, java.util.ArrayList<android.view.View!>);
+    method public abstract void scheduleRemoveTargets(Object, Object?, java.util.ArrayList<android.view.View!>?, Object?, java.util.ArrayList<android.view.View!>?, Object?, java.util.ArrayList<android.view.View!>?);
+    method public abstract void setEpicenter(Object, android.view.View?);
+    method public abstract void setEpicenter(Object, android.graphics.Rect);
+    method public void setListenerForTransitionEnd(androidx.fragment.app.Fragment, Object, androidx.core.os.CancellationSignal, Runnable);
+    method public abstract void setSharedElementTargets(Object, android.view.View, java.util.ArrayList<android.view.View!>);
+    method public abstract void swapSharedElementTargets(Object?, java.util.ArrayList<android.view.View!>?, java.util.ArrayList<android.view.View!>?);
+    method public abstract Object! wrapTransitionInSet(Object?);
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
+package androidx.fragment.app.strictmode {
+
+  public final class FragmentReuseViolation extends androidx.fragment.app.strictmode.Violation {
+    method public String getPreviousFragmentId();
+    property public final String previousFragmentId;
+  }
+
+  public final class FragmentStrictMode {
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy getDefaultPolicy();
+    method @VisibleForTesting public void onPolicyViolation(androidx.fragment.app.strictmode.Violation violation);
+    method public void setDefaultPolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy);
+    property public final androidx.fragment.app.strictmode.FragmentStrictMode.Policy defaultPolicy;
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode INSTANCE;
+  }
+
+  public static fun interface FragmentStrictMode.OnViolationListener {
+    method public void onViolation(androidx.fragment.app.strictmode.Violation violation);
+  }
+
+  public static final class FragmentStrictMode.Policy {
+    field public static final androidx.fragment.app.strictmode.FragmentStrictMode.Policy LAX;
+  }
+
+  public static final class FragmentStrictMode.Policy.Builder {
+    ctor public FragmentStrictMode.Policy.Builder();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(Class<? extends androidx.fragment.app.Fragment> fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder allowViolation(String fragmentClass, Class<? extends androidx.fragment.app.strictmode.Violation> violationClass);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy build();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentReuse();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectFragmentTagUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectRetainInstanceUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectSetUserVisibleHint();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectTargetFragmentUsage();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongFragmentContainer();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder detectWrongNestedHierarchy();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyDeath();
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyListener(androidx.fragment.app.strictmode.FragmentStrictMode.OnViolationListener listener);
+    method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyLog();
+  }
+
+  public final class FragmentTagUsageViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup? getParentContainer();
+    property public final android.view.ViewGroup? parentContainer;
+  }
+
+  public final class GetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class GetTargetFragmentRequestCodeUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public final class GetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+  }
+
+  public abstract class RetainInstanceUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public final class SetRetainInstanceUsageViolation extends androidx.fragment.app.strictmode.RetainInstanceUsageViolation {
+  }
+
+  public final class SetTargetFragmentUsageViolation extends androidx.fragment.app.strictmode.TargetFragmentUsageViolation {
+    method public int getRequestCode();
+    method public androidx.fragment.app.Fragment getTargetFragment();
+    property public final int requestCode;
+    property public final androidx.fragment.app.Fragment targetFragment;
+  }
+
+  public final class SetUserVisibleHintViolation extends androidx.fragment.app.strictmode.Violation {
+    method public boolean isVisibleToUser();
+    property public final boolean isVisibleToUser;
+  }
+
+  public abstract class TargetFragmentUsageViolation extends androidx.fragment.app.strictmode.Violation {
+  }
+
+  public abstract class Violation extends java.lang.RuntimeException {
+    method public final androidx.fragment.app.Fragment getFragment();
+    property public final androidx.fragment.app.Fragment fragment;
+  }
+
+  public final class WrongFragmentContainerViolation extends androidx.fragment.app.strictmode.Violation {
+    method public android.view.ViewGroup getContainer();
+    property public final android.view.ViewGroup container;
+  }
+
+  public final class WrongNestedHierarchyViolation extends androidx.fragment.app.strictmode.Violation {
+    method public int getContainerId();
+    method public androidx.fragment.app.Fragment getExpectedParentFragment();
+    property public final int containerId;
+    property public final androidx.fragment.app.Fragment expectedParentFragment;
+  }
+
+}
+
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
index 22f73cb..fb7c81e 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
@@ -56,7 +56,7 @@
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
 
-    private fun setupContainer(beginningFragment: PostponedFragment1 = PostponedFragment1()) {
+    private fun setupContainer(beginningFragment: TransitionFragment = PostponedFragment1()) {
         activityRule.setContentView(R.layout.simple_container)
         val fm = activityRule.activity.supportFragmentManager
 
@@ -1012,6 +1012,121 @@
         assertThat(fragment.startPostponedCountDownLatch.count).isEqualTo(0)
     }
 
+    @Test
+    fun testTimedPostponeNoLeak() {
+        val beginningFragment = PostponedFragment3(100000)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+    }
+
+    @Test
+    fun testTimedPostponeBeforeAttachedNoLeak() {
+        val beginningFragment = PostponedConstructorFragment(100000)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+    }
+
+    @Test
+    fun testTimedPostponeTwiceBeforeAttachedNoLeak() {
+        val beginningFragment = PostponedConstructorFragment(100000)
+        beginningFragment.postponeEnterTransition(1, TimeUnit.HOURS)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+    }
+
+    @Test
+    fun testTimedPostponeBeforeAttachedAndAfterAttachedNoLeak() {
+        val beginningFragment = PostponedConstructorAndAttachFragment(100000)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+    }
+
+    @Test
+    fun testTimedPostponeStartOnTestThreadNoLeak() {
+        val beginningFragment = PostponedFragment3(100000)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+
+        beginningFragment.startPostponedEnterTransition()
+    }
+
+    @Test
+    fun testTimedPostponeStartOnMainThreadNoLeak() {
+        val beginningFragment = PostponedFragment3(100000)
+        setupContainer(beginningFragment)
+
+        val fm = activityRule.activity.supportFragmentManager
+        val startBlue = activityRule.findBlue()
+
+        val fragment = TransitionFragment()
+        fm.beginTransaction()
+            .addSharedElement(startBlue, "blueSquare")
+            .replace(R.id.fragmentContainer, fragment)
+            .setReorderingAllowed(true)
+            .commit()
+
+        activityRule.waitForExecution()
+
+        activityRule.runOnUiThread {
+            beginningFragment.startPostponedEnterTransition()
+        }
+    }
+
     // Ensure that if startPostponedEnterTransaction is called before the timeout, there is no crash
     @Test
     fun testTimedPostponeStartPostponedCalledTwice() {
@@ -1327,10 +1442,11 @@
         }
     }
 
-    class PostponedConstructorFragment : TransitionFragment(R.layout.scene2) {
+    class PostponedConstructorFragment(duration: Long = 1000) :
+        TransitionFragment(R.layout.scene2) {
 
         init {
-            postponeEnterTransition(1000, TimeUnit.MILLISECONDS)
+            postponeEnterTransition(duration, TimeUnit.MILLISECONDS)
         }
 
         val startPostponedCountDownLatch = CountDownLatch(1)
@@ -1341,6 +1457,22 @@
         }
     }
 
+    class PostponedConstructorAndAttachFragment(private val duration: Long = 1000) :
+        TransitionFragment(R.layout.scene2) {
+
+        init {
+            postponeEnterTransition(duration, TimeUnit.MILLISECONDS)
+        }
+
+        override fun onCreateView(
+            inflater: LayoutInflater,
+            container: ViewGroup?,
+            savedInstanceState: Bundle?
+        ) = super.onCreateView(inflater, container, savedInstanceState).also {
+            postponeEnterTransition(duration, TimeUnit.MILLISECONDS)
+        }
+    }
+
     class CommitNowFragment : PostponedFragment1() {
         override fun onResume() {
             super.onResume()
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index c4081ff..53224f7 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -262,6 +262,9 @@
     // without Views.
     AnimationInfo mAnimationInfo;
 
+    // Handler used when the Fragment is postponed but not yet attached to the FragmentManager
+    Handler mPostponedHandler;
+
     // Runnable that is used to indicate if the Fragment has a postponed transition that is on a
     // timeout.
     Runnable mPostponedDurationRunnable = new Runnable() {
@@ -2852,14 +2855,16 @@
      */
     public final void postponeEnterTransition(long duration, @NonNull TimeUnit timeUnit) {
         ensureAnimationInfo().mEnterTransitionPostponed = true;
-        Handler handler;
-        if (mFragmentManager != null) {
-            handler = mFragmentManager.getHost().getHandler();
-        } else {
-            handler = new Handler(Looper.getMainLooper());
+        if (mPostponedHandler != null) {
+            mPostponedHandler.removeCallbacks(mPostponedDurationRunnable);
         }
-        handler.removeCallbacks(mPostponedDurationRunnable);
-        handler.postDelayed(mPostponedDurationRunnable, timeUnit.toMillis(duration));
+        if (mFragmentManager != null) {
+            mPostponedHandler = mFragmentManager.getHost().getHandler();
+        } else {
+            mPostponedHandler = new Handler(Looper.getMainLooper());
+        }
+        mPostponedHandler.removeCallbacks(mPostponedDurationRunnable);
+        mPostponedHandler.postDelayed(mPostponedDurationRunnable, timeUnit.toMillis(duration));
     }
 
     /**
@@ -2921,6 +2926,10 @@
                 // We've already posted our call, so we can execute directly
                 controller.executePendingOperations();
             }
+            if (mPostponedHandler != null) {
+                mPostponedHandler.removeCallbacks(mPostponedDurationRunnable);
+                mPostponedHandler = null;
+            }
         }
     }
 
diff --git a/glance/glance-appwidget/api/current.txt b/glance/glance-appwidget/api/current.txt
index 9010601..ca32bb4 100644
--- a/glance/glance-appwidget/api/current.txt
+++ b/glance/glance-appwidget/api/current.txt
@@ -251,35 +251,3 @@
 
 }
 
-package androidx.glance.appwidget.template {
-
-  public final class FreeformTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
-  }
-
-  public final class GalleryTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
-  }
-
-  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
-    ctor public GlanceTemplateAppWidget();
-    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
-    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
-    property public androidx.glance.appwidget.SizeMode sizeMode;
-    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
-    field public static final androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion Companion;
-  }
-
-  public static final class GlanceTemplateAppWidget.Companion {
-  }
-
-  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
-  }
-
-  public final class SingleEntityTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
-  }
-
-}
-
diff --git a/glance/glance-appwidget/api/public_plus_experimental_current.txt b/glance/glance-appwidget/api/public_plus_experimental_current.txt
index 0212a1d..7143945 100644
--- a/glance/glance-appwidget/api/public_plus_experimental_current.txt
+++ b/glance/glance-appwidget/api/public_plus_experimental_current.txt
@@ -265,35 +265,3 @@
 
 }
 
-package androidx.glance.appwidget.template {
-
-  public final class FreeformTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
-  }
-
-  public final class GalleryTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
-  }
-
-  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
-    ctor public GlanceTemplateAppWidget();
-    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
-    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
-    property public androidx.glance.appwidget.SizeMode sizeMode;
-    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
-    field public static final androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion Companion;
-  }
-
-  public static final class GlanceTemplateAppWidget.Companion {
-  }
-
-  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
-  }
-
-  public final class SingleEntityTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
-  }
-
-}
-
diff --git a/glance/glance-appwidget/api/restricted_current.txt b/glance/glance-appwidget/api/restricted_current.txt
index 9010601..ca32bb4 100644
--- a/glance/glance-appwidget/api/restricted_current.txt
+++ b/glance/glance-appwidget/api/restricted_current.txt
@@ -251,35 +251,3 @@
 
 }
 
-package androidx.glance.appwidget.template {
-
-  public final class FreeformTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
-  }
-
-  public final class GalleryTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
-  }
-
-  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
-    ctor public GlanceTemplateAppWidget();
-    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
-    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
-    property public androidx.glance.appwidget.SizeMode sizeMode;
-    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
-    field public static final androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion Companion;
-  }
-
-  public static final class GlanceTemplateAppWidget.Companion {
-  }
-
-  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
-  }
-
-  public final class SingleEntityTemplateLayoutsKt {
-    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
-  }
-
-}
-
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index 27cc5b3..0e11321 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -125,6 +125,20 @@
         </receiver>
 
         <receiver
+            android:name="androidx.glance.appwidget.demos.FontDemoAppWidgetReceiver"
+            android:label="@string/font_widget_name"
+            android:enabled="@bool/glance_appwidget_available"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+                <action android:name="android.intent.action.LOCALE_CHANGED" />
+            </intent-filter>
+            <meta-data
+                android:name="android.appwidget.provider"
+                android:resource="@xml/default_app_widget_info" />
+        </receiver>
+
+        <receiver
             android:name="androidx.glance.appwidget.demos.ScrollableAppWidgetReceiver"
             android:label="@string/scrollable_widget_name"
             android:enabled="@bool/glance_appwidget_available"
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/FontDemoWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/FontDemoWidget.kt
new file mode 100644
index 0000000..c5528c2
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/FontDemoWidget.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.glance.appwidget.demos
+
+import android.content.Context
+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.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.glance.Button
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.background
+import androidx.glance.appwidget.provideContent
+import androidx.glance.layout.Column
+import androidx.glance.layout.Spacer
+import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.fillMaxWidth
+import androidx.glance.layout.padding
+import androidx.glance.layout.size
+import androidx.glance.layout.wrapContentHeight
+import androidx.glance.text.FontFamily
+import androidx.glance.text.FontWeight
+import androidx.glance.text.Text
+import androidx.glance.text.TextAlign
+import androidx.glance.text.TextStyle
+
+/**
+ * Sample AppWidget to demonstrate font changes.
+ */
+class FontDemoWidget : GlanceAppWidget() {
+    override val sizeMode: SizeMode = SizeMode.Exact
+
+    override suspend fun provideGlance(
+        context: Context,
+        id: GlanceId
+    ) = provideContent {
+        FontDemoContent()
+    }
+
+    @Composable
+    private fun FontDemoContent() {
+        // This will reset any time the process is killed, but it isn't important as it's just to
+        // showcase different fonts.
+        var font by remember { mutableStateOf(FontFamily.Serif) }
+
+        Column(
+            modifier = GlanceModifier.fillMaxSize()
+                .background(day = Color.LightGray, night = Color.DarkGray).padding(8.dp),
+        ) {
+            Text(
+                "Font Demo Widget",
+                modifier = GlanceModifier.fillMaxWidth().wrapContentHeight(),
+                style = TextStyle(
+                    fontWeight = FontWeight.Bold,
+                    fontSize = 24.sp,
+                    textAlign = TextAlign.Center
+                )
+            )
+            Spacer(GlanceModifier.size(15.dp))
+
+            Text(
+                "Font: " + font.family,
+                style = TextStyle(fontSize = 20.sp, fontFamily = FontFamily.SansSerif)
+            )
+            Spacer(GlanceModifier.size(15.dp))
+            Text(
+                "The quick brown fox jumps over the lazy dog.",
+                style = TextStyle(fontSize = 18.sp, fontFamily = font)
+            )
+            Spacer(GlanceModifier.defaultWeight())
+            Button(text = "Toggle font", onClick = {
+                font = when (font) {
+                    FontFamily.Serif -> FontFamily.SansSerif
+                    FontFamily.SansSerif -> FontFamily.Cursive
+                    FontFamily.Cursive -> FontFamily.Monospace
+                    FontFamily.Monospace -> FontFamily.Serif
+                    else -> FontFamily.SansSerif
+                }
+            })
+        }
+    }
+}
+
+class FontDemoAppWidgetReceiver : GlanceAppWidgetReceiver() {
+    override val glanceAppWidget: GlanceAppWidget = FontDemoWidget()
+}
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
index 0076752..638118d 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
@@ -27,6 +27,7 @@
     <string name="resizing_widget_name">Resizing Widget</string>
     <string name="compound_button_widget_name">Compound buttons Widget</string>
     <string name="error_widget_name">Error UI Widget</string>
+    <string name="font_widget_name">Font Demo Widget</string>
     <string name="scrollable_widget_name">Scrollable Widget</string>
     <string name="image_widget_name">Image Widget</string>
     <string name="ripple_widget_name">Ripple Widget</string>
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
index de50aac..2430d3f 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
@@ -38,6 +38,7 @@
 import androidx.work.WorkManager
 import androidx.work.testing.WorkManagerTestInitHelper
 import com.google.common.truth.Truth.assertThat
+import java.lang.ref.WeakReference
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import kotlin.test.assertIs
@@ -82,15 +83,16 @@
 
     private val mInnerRules = RuleChain.outerRule(mActivityRule).around(mOrientationRule)
 
+    private lateinit var mMaybeHostView: WeakReference<TestAppWidgetHostView?>
+
     private var mHostStarted = false
-    private var mMaybeHostView: TestAppWidgetHostView? = null
     private var mAppWidgetId = 0
     private val mScenario: ActivityScenario<AppWidgetHostTestActivity>
         get() = mActivityRule.scenario
     private val mContext = ApplicationProvider.getApplicationContext<Context>()
 
     val mHostView: TestAppWidgetHostView
-        get() = checkNotNull(mMaybeHostView) { "No app widget installed on the host" }
+        get() = checkNotNull(mMaybeHostView.get()) { "No app widget installed on the host" }
 
     val appWidgetId: Int get() = mAppWidgetId
 
@@ -118,14 +120,12 @@
         mHostStarted = true
 
         mActivityRule.scenario.onActivity { activity ->
-            mMaybeHostView = activity.bindAppWidget(mPortraitSize, mLandscapeSize)
+            mMaybeHostView = WeakReference(activity.bindAppWidget(mPortraitSize, mLandscapeSize))
         }
 
-        val hostView = checkNotNull(mMaybeHostView) { "Host view wasn't successfully started" }
-
         runAndWaitForChildren {
-            mAppWidgetId = hostView.appWidgetId
-            hostView.waitForRemoteViews()
+            mAppWidgetId = mHostView.appWidgetId
+            mHostView.waitForRemoteViews()
         }
     }
 
@@ -136,8 +136,7 @@
      * This should not be called from the main thread, i.e. in [onHostView] or [onHostActivity].
      */
     suspend fun runAndWaitForUpdate(block: suspend () -> Unit) {
-        val hostView = checkNotNull(mMaybeHostView) { "Host view wasn't successfully started" }
-        hostView.resetRemoteViewsLatch()
+        mHostView.resetRemoteViewsLatch()
         withContext(Dispatchers.Main) { block() }
 
         // b/267494219 these tests are currently flaking due to possible changes to the views after
@@ -147,7 +146,7 @@
 
         // Do not wait on the main thread so that the UI handlers can run.
         runAndWaitForChildren {
-            hostView.waitForRemoteViews()
+            mHostView.waitForRemoteViews()
         }
     }
 
@@ -166,8 +165,7 @@
 
     fun removeAppWidget() {
         mActivityRule.scenario.onActivity { activity ->
-            val hostView = checkNotNull(mMaybeHostView) { "No app widget to remove" }
-            activity.deleteAppWidget(hostView)
+            activity.deleteAppWidget(mHostView)
         }
     }
 
@@ -275,7 +273,7 @@
         mPortraitSize = portrait
         if (!mHostStarted) return
 
-        val hostView = mMaybeHostView
+        val hostView = mMaybeHostView.get()
         if (hostView != null) {
             mScenario.onActivity {
                 hostView.setSizes(portrait, landscape)
diff --git a/glance/glance-template/api/current.txt b/glance/glance-template/api/current.txt
new file mode 100644
index 0000000..98082dc
--- /dev/null
+++ b/glance/glance-template/api/current.txt
@@ -0,0 +1,256 @@
+// Signature format: 4.0
+package androidx.glance.template {
+
+  public final class ActionBlock {
+    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
+    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
+    method public int getType();
+    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
+    property public final int type;
+  }
+
+  @kotlin.jvm.JvmInline public final value class AspectRatio {
+    field public static final androidx.glance.template.AspectRatio.Companion Companion;
+  }
+
+  public static final class AspectRatio.Companion {
+    method public int getRatio16x9();
+    method public int getRatio1x1();
+    method public int getRatio2x3();
+    property public final int Ratio16x9;
+    property public final int Ratio1x1;
+    property public final int Ratio2x3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ButtonType {
+    field public static final androidx.glance.template.ButtonType.Companion Companion;
+  }
+
+  public static final class ButtonType.Companion {
+    method public int getFab();
+    method public int getIcon();
+    method public int getText();
+    method public int getTextIcon();
+    property public final int Fab;
+    property public final int Icon;
+    property public final int Text;
+    property public final int TextIcon;
+  }
+
+  public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
+  }
+
+  public final class FreeformTemplateData {
+    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
+    method public androidx.glance.template.TemplateImageButton? getActionIcon();
+    method public androidx.glance.unit.ColorProvider getBackgroundColor();
+    method public androidx.glance.ImageProvider? getBackgroundImage();
+    method public androidx.glance.template.TemplateText? getHeader();
+    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
+    method public androidx.glance.template.TemplateText? getSubtitle();
+    method public androidx.glance.template.TemplateText? getTitle();
+    property public final androidx.glance.template.TemplateImageButton? actionIcon;
+    property public final androidx.glance.unit.ColorProvider backgroundColor;
+    property public final androidx.glance.ImageProvider? backgroundImage;
+    property public final androidx.glance.template.TemplateText? header;
+    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
+    property public final androidx.glance.template.TemplateText? subtitle;
+    property public final androidx.glance.template.TemplateText? title;
+  }
+
+  public final class FreeformTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
+  }
+
+  public final class GalleryTemplateData {
+    ctor public GalleryTemplateData(androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, androidx.glance.template.ImageBlock galleryImageBlock, optional androidx.glance.template.HeaderBlock? header, optional androidx.glance.template.ActionBlock? mainActionBlock);
+    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
+    method public androidx.glance.template.HeaderBlock? getHeader();
+    method public androidx.glance.template.ActionBlock? getMainActionBlock();
+    method public androidx.glance.template.ImageBlock getMainImageBlock();
+    method public androidx.glance.template.TextBlock getMainTextBlock();
+    property public final androidx.glance.template.ImageBlock galleryImageBlock;
+    property public final androidx.glance.template.HeaderBlock? header;
+    property public final androidx.glance.template.ActionBlock? mainActionBlock;
+    property public final androidx.glance.template.ImageBlock mainImageBlock;
+    property public final androidx.glance.template.TextBlock mainTextBlock;
+  }
+
+  public final class GalleryTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
+  }
+
+  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
+    ctor public GlanceTemplateAppWidget();
+    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
+    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
+    property public androidx.glance.appwidget.SizeMode sizeMode;
+    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
+    field public static final androidx.glance.template.GlanceTemplateAppWidget.Companion Companion;
+  }
+
+  public static final class GlanceTemplateAppWidget.Companion {
+  }
+
+  public final class HeaderBlock {
+    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
+    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
+    method public androidx.glance.template.TemplateText getText();
+    property public final androidx.glance.template.TemplateImageWithDescription? icon;
+    property public final androidx.glance.template.TemplateText text;
+  }
+
+  public final class ImageBlock {
+    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
+    method public int getAspectRatio();
+    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
+    method public int getPriority();
+    method public int getSize();
+    property public final int aspectRatio;
+    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
+    property public final int priority;
+    property public final int size;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ImageSize {
+    field public static final androidx.glance.template.ImageSize.Companion Companion;
+  }
+
+  public static final class ImageSize.Companion {
+    method public int getLarge();
+    method public int getMedium();
+    method public int getSmall();
+    method public int getUndefined();
+    property public final int Large;
+    property public final int Medium;
+    property public final int Small;
+    property public final int Undefined;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ListStyle {
+    field public static final androidx.glance.template.ListStyle.Companion Companion;
+  }
+
+  public static final class ListStyle.Companion {
+    method public int getBrief();
+    method public int getFull();
+    property public final int Brief;
+    property public final int Full;
+  }
+
+  public final class ListTemplateData {
+    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
+    method public int getListStyle();
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
+    property public final int listStyle;
+  }
+
+  public final class ListTemplateItem {
+    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock textBlock;
+  }
+
+  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
+  }
+
+  public final class SingleEntityTemplateData {
+    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock? getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock? textBlock;
+  }
+
+  public final class SingleEntityTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
+  }
+
+  public abstract sealed class TemplateButton {
+    method public final androidx.glance.action.Action getAction();
+    property public final androidx.glance.action.Action action;
+  }
+
+  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
+    method public androidx.glance.template.TemplateImageWithDescription getImage();
+    property public final androidx.glance.template.TemplateImageWithDescription image;
+  }
+
+  public final class TemplateImageWithDescription {
+    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
+    method public float getCornerRadius();
+    method public String getDescription();
+    method public androidx.glance.ImageProvider getImage();
+    property public final float cornerRadius;
+    property public final String description;
+    property public final androidx.glance.ImageProvider image;
+  }
+
+  public enum TemplateMode {
+    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.glance.template.TemplateMode[] values();
+    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
+    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
+    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
+  }
+
+  public final class TemplateText {
+    ctor public TemplateText(String text, optional int type);
+    method public String getText();
+    method public int getType();
+    property public final String text;
+    property public final int type;
+  }
+
+  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
+    method public String getText();
+    property public final String text;
+  }
+
+  public final class TextBlock {
+    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
+    method public int getPriority();
+    method public androidx.glance.template.TemplateText getText1();
+    method public androidx.glance.template.TemplateText? getText2();
+    method public androidx.glance.template.TemplateText? getText3();
+    property public final int priority;
+    property public final androidx.glance.template.TemplateText text1;
+    property public final androidx.glance.template.TemplateText? text2;
+    property public final androidx.glance.template.TemplateText? text3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class TextType {
+    field public static final androidx.glance.template.TextType.Companion Companion;
+  }
+
+  public static final class TextType.Companion {
+    method public int getBody();
+    method public int getDisplay();
+    method public int getHeadline();
+    method public int getLabel();
+    method public int getTitle();
+    property public final int Body;
+    property public final int Display;
+    property public final int Headline;
+    property public final int Label;
+    property public final int Title;
+  }
+
+}
+
diff --git a/glance/glance-template/api/public_plus_experimental_current.txt b/glance/glance-template/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..98082dc
--- /dev/null
+++ b/glance/glance-template/api/public_plus_experimental_current.txt
@@ -0,0 +1,256 @@
+// Signature format: 4.0
+package androidx.glance.template {
+
+  public final class ActionBlock {
+    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
+    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
+    method public int getType();
+    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
+    property public final int type;
+  }
+
+  @kotlin.jvm.JvmInline public final value class AspectRatio {
+    field public static final androidx.glance.template.AspectRatio.Companion Companion;
+  }
+
+  public static final class AspectRatio.Companion {
+    method public int getRatio16x9();
+    method public int getRatio1x1();
+    method public int getRatio2x3();
+    property public final int Ratio16x9;
+    property public final int Ratio1x1;
+    property public final int Ratio2x3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ButtonType {
+    field public static final androidx.glance.template.ButtonType.Companion Companion;
+  }
+
+  public static final class ButtonType.Companion {
+    method public int getFab();
+    method public int getIcon();
+    method public int getText();
+    method public int getTextIcon();
+    property public final int Fab;
+    property public final int Icon;
+    property public final int Text;
+    property public final int TextIcon;
+  }
+
+  public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
+  }
+
+  public final class FreeformTemplateData {
+    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
+    method public androidx.glance.template.TemplateImageButton? getActionIcon();
+    method public androidx.glance.unit.ColorProvider getBackgroundColor();
+    method public androidx.glance.ImageProvider? getBackgroundImage();
+    method public androidx.glance.template.TemplateText? getHeader();
+    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
+    method public androidx.glance.template.TemplateText? getSubtitle();
+    method public androidx.glance.template.TemplateText? getTitle();
+    property public final androidx.glance.template.TemplateImageButton? actionIcon;
+    property public final androidx.glance.unit.ColorProvider backgroundColor;
+    property public final androidx.glance.ImageProvider? backgroundImage;
+    property public final androidx.glance.template.TemplateText? header;
+    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
+    property public final androidx.glance.template.TemplateText? subtitle;
+    property public final androidx.glance.template.TemplateText? title;
+  }
+
+  public final class FreeformTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
+  }
+
+  public final class GalleryTemplateData {
+    ctor public GalleryTemplateData(androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, androidx.glance.template.ImageBlock galleryImageBlock, optional androidx.glance.template.HeaderBlock? header, optional androidx.glance.template.ActionBlock? mainActionBlock);
+    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
+    method public androidx.glance.template.HeaderBlock? getHeader();
+    method public androidx.glance.template.ActionBlock? getMainActionBlock();
+    method public androidx.glance.template.ImageBlock getMainImageBlock();
+    method public androidx.glance.template.TextBlock getMainTextBlock();
+    property public final androidx.glance.template.ImageBlock galleryImageBlock;
+    property public final androidx.glance.template.HeaderBlock? header;
+    property public final androidx.glance.template.ActionBlock? mainActionBlock;
+    property public final androidx.glance.template.ImageBlock mainImageBlock;
+    property public final androidx.glance.template.TextBlock mainTextBlock;
+  }
+
+  public final class GalleryTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
+  }
+
+  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
+    ctor public GlanceTemplateAppWidget();
+    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
+    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
+    property public androidx.glance.appwidget.SizeMode sizeMode;
+    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
+    field public static final androidx.glance.template.GlanceTemplateAppWidget.Companion Companion;
+  }
+
+  public static final class GlanceTemplateAppWidget.Companion {
+  }
+
+  public final class HeaderBlock {
+    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
+    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
+    method public androidx.glance.template.TemplateText getText();
+    property public final androidx.glance.template.TemplateImageWithDescription? icon;
+    property public final androidx.glance.template.TemplateText text;
+  }
+
+  public final class ImageBlock {
+    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
+    method public int getAspectRatio();
+    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
+    method public int getPriority();
+    method public int getSize();
+    property public final int aspectRatio;
+    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
+    property public final int priority;
+    property public final int size;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ImageSize {
+    field public static final androidx.glance.template.ImageSize.Companion Companion;
+  }
+
+  public static final class ImageSize.Companion {
+    method public int getLarge();
+    method public int getMedium();
+    method public int getSmall();
+    method public int getUndefined();
+    property public final int Large;
+    property public final int Medium;
+    property public final int Small;
+    property public final int Undefined;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ListStyle {
+    field public static final androidx.glance.template.ListStyle.Companion Companion;
+  }
+
+  public static final class ListStyle.Companion {
+    method public int getBrief();
+    method public int getFull();
+    property public final int Brief;
+    property public final int Full;
+  }
+
+  public final class ListTemplateData {
+    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
+    method public int getListStyle();
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
+    property public final int listStyle;
+  }
+
+  public final class ListTemplateItem {
+    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock textBlock;
+  }
+
+  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
+  }
+
+  public final class SingleEntityTemplateData {
+    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock? getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock? textBlock;
+  }
+
+  public final class SingleEntityTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
+  }
+
+  public abstract sealed class TemplateButton {
+    method public final androidx.glance.action.Action getAction();
+    property public final androidx.glance.action.Action action;
+  }
+
+  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
+    method public androidx.glance.template.TemplateImageWithDescription getImage();
+    property public final androidx.glance.template.TemplateImageWithDescription image;
+  }
+
+  public final class TemplateImageWithDescription {
+    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
+    method public float getCornerRadius();
+    method public String getDescription();
+    method public androidx.glance.ImageProvider getImage();
+    property public final float cornerRadius;
+    property public final String description;
+    property public final androidx.glance.ImageProvider image;
+  }
+
+  public enum TemplateMode {
+    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.glance.template.TemplateMode[] values();
+    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
+    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
+    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
+  }
+
+  public final class TemplateText {
+    ctor public TemplateText(String text, optional int type);
+    method public String getText();
+    method public int getType();
+    property public final String text;
+    property public final int type;
+  }
+
+  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
+    method public String getText();
+    property public final String text;
+  }
+
+  public final class TextBlock {
+    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
+    method public int getPriority();
+    method public androidx.glance.template.TemplateText getText1();
+    method public androidx.glance.template.TemplateText? getText2();
+    method public androidx.glance.template.TemplateText? getText3();
+    property public final int priority;
+    property public final androidx.glance.template.TemplateText text1;
+    property public final androidx.glance.template.TemplateText? text2;
+    property public final androidx.glance.template.TemplateText? text3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class TextType {
+    field public static final androidx.glance.template.TextType.Companion Companion;
+  }
+
+  public static final class TextType.Companion {
+    method public int getBody();
+    method public int getDisplay();
+    method public int getHeadline();
+    method public int getLabel();
+    method public int getTitle();
+    property public final int Body;
+    property public final int Display;
+    property public final int Headline;
+    property public final int Label;
+    property public final int Title;
+  }
+
+}
+
diff --git a/glance/glance-template/api/res-current.txt b/glance/glance-template/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/glance/glance-template/api/res-current.txt
diff --git a/glance/glance-template/api/restricted_current.txt b/glance/glance-template/api/restricted_current.txt
new file mode 100644
index 0000000..98082dc
--- /dev/null
+++ b/glance/glance-template/api/restricted_current.txt
@@ -0,0 +1,256 @@
+// Signature format: 4.0
+package androidx.glance.template {
+
+  public final class ActionBlock {
+    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
+    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
+    method public int getType();
+    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
+    property public final int type;
+  }
+
+  @kotlin.jvm.JvmInline public final value class AspectRatio {
+    field public static final androidx.glance.template.AspectRatio.Companion Companion;
+  }
+
+  public static final class AspectRatio.Companion {
+    method public int getRatio16x9();
+    method public int getRatio1x1();
+    method public int getRatio2x3();
+    property public final int Ratio16x9;
+    property public final int Ratio1x1;
+    property public final int Ratio2x3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ButtonType {
+    field public static final androidx.glance.template.ButtonType.Companion Companion;
+  }
+
+  public static final class ButtonType.Companion {
+    method public int getFab();
+    method public int getIcon();
+    method public int getText();
+    method public int getTextIcon();
+    property public final int Fab;
+    property public final int Icon;
+    property public final int Text;
+    property public final int TextIcon;
+  }
+
+  public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
+  }
+
+  public final class FreeformTemplateData {
+    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
+    method public androidx.glance.template.TemplateImageButton? getActionIcon();
+    method public androidx.glance.unit.ColorProvider getBackgroundColor();
+    method public androidx.glance.ImageProvider? getBackgroundImage();
+    method public androidx.glance.template.TemplateText? getHeader();
+    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
+    method public androidx.glance.template.TemplateText? getSubtitle();
+    method public androidx.glance.template.TemplateText? getTitle();
+    property public final androidx.glance.template.TemplateImageButton? actionIcon;
+    property public final androidx.glance.unit.ColorProvider backgroundColor;
+    property public final androidx.glance.ImageProvider? backgroundImage;
+    property public final androidx.glance.template.TemplateText? header;
+    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
+    property public final androidx.glance.template.TemplateText? subtitle;
+    property public final androidx.glance.template.TemplateText? title;
+  }
+
+  public final class FreeformTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void FreeformTemplate(androidx.glance.template.FreeformTemplateData data);
+  }
+
+  public final class GalleryTemplateData {
+    ctor public GalleryTemplateData(androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, androidx.glance.template.ImageBlock galleryImageBlock, optional androidx.glance.template.HeaderBlock? header, optional androidx.glance.template.ActionBlock? mainActionBlock);
+    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
+    method public androidx.glance.template.HeaderBlock? getHeader();
+    method public androidx.glance.template.ActionBlock? getMainActionBlock();
+    method public androidx.glance.template.ImageBlock getMainImageBlock();
+    method public androidx.glance.template.TextBlock getMainTextBlock();
+    property public final androidx.glance.template.ImageBlock galleryImageBlock;
+    property public final androidx.glance.template.HeaderBlock? header;
+    property public final androidx.glance.template.ActionBlock? mainActionBlock;
+    property public final androidx.glance.template.ImageBlock mainImageBlock;
+    property public final androidx.glance.template.TextBlock mainTextBlock;
+  }
+
+  public final class GalleryTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void GalleryTemplate(androidx.glance.template.GalleryTemplateData data);
+  }
+
+  public abstract class GlanceTemplateAppWidget extends androidx.glance.appwidget.GlanceAppWidget {
+    ctor public GlanceTemplateAppWidget();
+    method @androidx.compose.runtime.Composable @androidx.glance.GlanceComposable public abstract void TemplateContent();
+    method public final suspend Object? provideGlance(android.content.Context context, androidx.glance.GlanceId id, kotlin.coroutines.Continuation<?>);
+    property public androidx.glance.appwidget.SizeMode sizeMode;
+    property public androidx.glance.state.GlanceStateDefinition<?>? stateDefinition;
+    field public static final androidx.glance.template.GlanceTemplateAppWidget.Companion Companion;
+  }
+
+  public static final class GlanceTemplateAppWidget.Companion {
+  }
+
+  public final class HeaderBlock {
+    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
+    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
+    method public androidx.glance.template.TemplateText getText();
+    property public final androidx.glance.template.TemplateImageWithDescription? icon;
+    property public final androidx.glance.template.TemplateText text;
+  }
+
+  public final class ImageBlock {
+    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
+    method public int getAspectRatio();
+    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
+    method public int getPriority();
+    method public int getSize();
+    property public final int aspectRatio;
+    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
+    property public final int priority;
+    property public final int size;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ImageSize {
+    field public static final androidx.glance.template.ImageSize.Companion Companion;
+  }
+
+  public static final class ImageSize.Companion {
+    method public int getLarge();
+    method public int getMedium();
+    method public int getSmall();
+    method public int getUndefined();
+    property public final int Large;
+    property public final int Medium;
+    property public final int Small;
+    property public final int Undefined;
+  }
+
+  @kotlin.jvm.JvmInline public final value class ListStyle {
+    field public static final androidx.glance.template.ListStyle.Companion Companion;
+  }
+
+  public static final class ListStyle.Companion {
+    method public int getBrief();
+    method public int getFull();
+    property public final int Brief;
+    property public final int Full;
+  }
+
+  public final class ListTemplateData {
+    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
+    method public int getListStyle();
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
+    property public final int listStyle;
+  }
+
+  public final class ListTemplateItem {
+    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock textBlock;
+  }
+
+  @androidx.glance.GlanceComposable public final class ListTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void ListTemplate(androidx.glance.template.ListTemplateData data);
+  }
+
+  public final class SingleEntityTemplateData {
+    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
+    method public androidx.glance.template.ActionBlock? getActionBlock();
+    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
+    method public androidx.glance.template.ImageBlock? getImageBlock();
+    method public androidx.glance.template.TextBlock? getTextBlock();
+    property public final androidx.glance.template.ActionBlock? actionBlock;
+    property public final androidx.glance.template.HeaderBlock? headerBlock;
+    property public final androidx.glance.template.ImageBlock? imageBlock;
+    property public final androidx.glance.template.TextBlock? textBlock;
+  }
+
+  public final class SingleEntityTemplateLayoutsKt {
+    method @androidx.compose.runtime.Composable public static void SingleEntityTemplate(androidx.glance.template.SingleEntityTemplateData data);
+  }
+
+  public abstract sealed class TemplateButton {
+    method public final androidx.glance.action.Action getAction();
+    property public final androidx.glance.action.Action action;
+  }
+
+  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
+    method public androidx.glance.template.TemplateImageWithDescription getImage();
+    property public final androidx.glance.template.TemplateImageWithDescription image;
+  }
+
+  public final class TemplateImageWithDescription {
+    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
+    method public float getCornerRadius();
+    method public String getDescription();
+    method public androidx.glance.ImageProvider getImage();
+    property public final float cornerRadius;
+    property public final String description;
+    property public final androidx.glance.ImageProvider image;
+  }
+
+  public enum TemplateMode {
+    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.glance.template.TemplateMode[] values();
+    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
+    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
+    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
+  }
+
+  public final class TemplateText {
+    ctor public TemplateText(String text, optional int type);
+    method public String getText();
+    method public int getType();
+    property public final String text;
+    property public final int type;
+  }
+
+  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
+    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
+    method public String getText();
+    property public final String text;
+  }
+
+  public final class TextBlock {
+    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
+    method public int getPriority();
+    method public androidx.glance.template.TemplateText getText1();
+    method public androidx.glance.template.TemplateText? getText2();
+    method public androidx.glance.template.TemplateText? getText3();
+    property public final int priority;
+    property public final androidx.glance.template.TemplateText text1;
+    property public final androidx.glance.template.TemplateText? text2;
+    property public final androidx.glance.template.TemplateText? text3;
+  }
+
+  @kotlin.jvm.JvmInline public final value class TextType {
+    field public static final androidx.glance.template.TextType.Companion Companion;
+  }
+
+  public static final class TextType.Companion {
+    method public int getBody();
+    method public int getDisplay();
+    method public int getHeadline();
+    method public int getLabel();
+    method public int getTitle();
+    property public final int Body;
+    property public final int Display;
+    property public final int Headline;
+    property public final int Label;
+    property public final int Title;
+  }
+
+}
+
diff --git a/glance/glance-template/build.gradle b/glance/glance-template/build.gradle
new file mode 100644
index 0000000..1fd8868
--- /dev/null
+++ b/glance/glance-template/build.gradle
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryType
+import androidx.build.Publish
+import androidx.build.AndroidXComposePlugin
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXComposePlugin")
+}
+
+// Disable multi-platform; this will only be used on Android.
+AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project, /* isMultiplatformEnabled= */false)
+
+dependencies {
+    api(project(":glance:glance"))
+    api(project(":glance:glance-appwidget"))
+    api("androidx.annotation:annotation:1.2.0")
+    api("androidx.compose.runtime:runtime:1.1.1")
+    api("androidx.compose.ui:ui-graphics:1.1.1")
+    api("androidx.compose.ui:ui-unit:1.1.1")
+    api("androidx.datastore:datastore-core:1.0.0")
+    api("androidx.datastore:datastore-preferences-core:1.0.0")
+    api("androidx.datastore:datastore-preferences:1.0.0")
+
+    implementation("androidx.annotation:annotation:1.1.0")
+    implementation("androidx.work:work-runtime:2.7.1")
+    implementation("androidx.work:work-runtime-ktx:2.7.1")
+    implementation(libs.kotlinStdlib)
+    implementation(project(":compose:runtime:runtime"))
+
+    // Force upgrade since 1.2.0 is not compatible with latest lint.
+    implementation("androidx.annotation:annotation-experimental:1.3.0")
+
+    testImplementation(libs.robolectric)
+    testImplementation(libs.testCore)
+    testImplementation(libs.testRules)
+    testImplementation(libs.testRunner)
+    testImplementation(libs.truth)
+    testImplementation(libs.junit)
+    testImplementation(libs.kotlinCoroutinesTest)
+    testImplementation(libs.kotlinTest)
+    testImplementation(libs.kotlinReflect)
+    testImplementation(libs.mockitoCore4)
+    testImplementation(libs.mockitoKotlin4)
+    testImplementation("androidx.datastore:datastore-core:1.0.0")
+    testImplementation("androidx.datastore:datastore-preferences-core:1.0.0")
+    testImplementation("androidx.datastore:datastore-preferences:1.0.0")
+    testImplementation("androidx.room:room-runtime:2.4.3")
+    testImplementation("androidx.work:work-testing:2.7.1")
+    testImplementation("com.google.android.material:material:1.6.0")
+}
+
+android {
+    // Use Robolectric 4.+
+    testOptions.unitTests.includeAndroidResources = true
+    resourcePrefix "glance_template_"
+    namespace "androidx.glance.template"
+}
+
+androidx {
+    name = "Glance Templates Library"
+    type = LibraryType.PUBLISHED_LIBRARY
+    inceptionYear = "2021"
+    description = "Glance allows developers to build layouts for remote surfaces using a Jetpack " +
+            "Compose-style API."
+    targetsJavaConsumers = false
+}
diff --git a/glance/glance-appwidget/integration-tests/template-demos/build.gradle b/glance/glance-template/integration-tests/template-demos/build.gradle
similarity index 97%
rename from glance/glance-appwidget/integration-tests/template-demos/build.gradle
rename to glance/glance-template/integration-tests/template-demos/build.gradle
index cec0492..e4f4972 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/build.gradle
+++ b/glance/glance-template/integration-tests/template-demos/build.gradle
@@ -27,6 +27,7 @@
     implementation(libs.kotlinStdlib)
     implementation(project(":glance:glance"))
     implementation(project(":glance:glance-appwidget"))
+    implementation(project(":glance:glance-template"))
     implementation(project(":glance:glance-material"))
     implementation(project(":glance:glance-material3"))
     implementation("androidx.activity:activity:1.4.0")
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml b/glance/glance-template/integration-tests/template-demos/src/main/AndroidManifest.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/AndroidManifest.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt
similarity index 96%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt
rename to glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt
index 6360174..5ee0b7f 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt
+++ b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/DemoOverrideWidget.kt
@@ -24,8 +24,8 @@
 import androidx.glance.ImageProvider
 import androidx.glance.appwidget.GlanceAppWidget
 import androidx.glance.appwidget.GlanceAppWidgetReceiver
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget
-import androidx.glance.appwidget.template.SingleEntityTemplate
+import androidx.glance.template.GlanceTemplateAppWidget
+import androidx.glance.template.SingleEntityTemplate
 import androidx.glance.background
 import androidx.glance.layout.Alignment
 import androidx.glance.layout.Column
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt
similarity index 97%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt
rename to glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt
index bbf0c0b..04ec6f2 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt
+++ b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/GalleryDemoWidget.kt
@@ -22,8 +22,8 @@
 import androidx.glance.appwidget.GlanceAppWidget
 import androidx.glance.appwidget.GlanceAppWidgetReceiver
 import androidx.glance.appwidget.action.actionRunCallback
-import androidx.glance.appwidget.template.GalleryTemplate
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget
+import androidx.glance.template.GalleryTemplate
+import androidx.glance.template.GlanceTemplateAppWidget
 import androidx.glance.template.ActionBlock
 import androidx.glance.template.AspectRatio
 import androidx.glance.template.GalleryTemplateData
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt
similarity index 98%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt
rename to glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt
index fd1b18a..354d8b2 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt
+++ b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/ListDemoWidget.kt
@@ -34,8 +34,8 @@
 import androidx.glance.appwidget.action.ActionCallback
 import androidx.glance.appwidget.action.actionRunCallback
 import androidx.glance.appwidget.state.updateAppWidgetState
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget
-import androidx.glance.appwidget.template.ListTemplate
+import androidx.glance.template.GlanceTemplateAppWidget
+import androidx.glance.template.ListTemplate
 import androidx.glance.currentState
 import androidx.glance.template.ActionBlock
 import androidx.glance.template.HeaderBlock
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/PalmLeafScheme.kt b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/PalmLeafScheme.kt
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/PalmLeafScheme.kt
rename to glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/PalmLeafScheme.kt
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt
similarity index 96%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt
rename to glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt
index 1af3725..36e6d78 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt
+++ b/glance/glance-template/integration-tests/template-demos/src/main/java/androidx/glance/appwidget/template/demos/SingleEntityDemoWidget.kt
@@ -29,8 +29,8 @@
 import androidx.glance.appwidget.action.ActionCallback
 import androidx.glance.appwidget.action.actionRunCallback
 import androidx.glance.appwidget.state.updateAppWidgetState
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget
-import androidx.glance.appwidget.template.SingleEntityTemplate
+import androidx.glance.template.GlanceTemplateAppWidget
+import androidx.glance.template.SingleEntityTemplate
 import androidx.glance.currentState
 import androidx.glance.template.ActionBlock
 import androidx.glance.template.HeaderBlock
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable-nodpi/palm_leaf.png b/glance/glance-template/integration-tests/template-demos/src/main/res/drawable-nodpi/palm_leaf.png
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable-nodpi/palm_leaf.png
rename to glance/glance-template/integration-tests/template-demos/src/main/res/drawable-nodpi/palm_leaf.png
Binary files differ
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable/ic_bookmark.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/drawable/ic_bookmark.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable/ic_bookmark.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/drawable/ic_bookmark.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable/ic_widgets.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/drawable/ic_widgets.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/drawable/ic_widgets.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/drawable/ic_widgets.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/values-night/colors.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/values-night/colors.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/values-night/colors.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/values-night/colors.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/values/colors.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/values/colors.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/values/colors.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/values/colors.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/values/strings.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/values/strings.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/values/strings.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/values/strings.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/default_app_widget_info.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/xml/default_app_widget_info.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/default_app_widget_info.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/xml/default_app_widget_info.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/gallery_app_widget_info.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/xml/gallery_app_widget_info.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/gallery_app_widget_info.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/xml/gallery_app_widget_info.xml
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/list_app_widget_info.xml b/glance/glance-template/integration-tests/template-demos/src/main/res/xml/list_app_widget_info.xml
similarity index 100%
rename from glance/glance-appwidget/integration-tests/template-demos/src/main/res/xml/list_app_widget_info.xml
rename to glance/glance-template/integration-tests/template-demos/src/main/res/xml/list_app_widget_info.xml
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt b/glance/glance-template/src/main/java/androidx/glance/template/CompositionLocals.kt
similarity index 93%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/CompositionLocals.kt
index 5a9840b..84f2c72 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/CompositionLocals.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/FreeformTemplateData.kt b/glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateData.kt
similarity index 97%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/FreeformTemplateData.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateData.kt
index 245097e..8c1b87b 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/FreeformTemplateData.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/FreeformTemplateLayouts.kt b/glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateLayouts.kt
similarity index 91%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/FreeformTemplateLayouts.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateLayouts.kt
index 115feec..3b398c1 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/FreeformTemplateLayouts.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/FreeformTemplateLayouts.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.unit.dp
@@ -26,11 +26,6 @@
 import androidx.glance.layout.ContentScale
 import androidx.glance.layout.fillMaxSize
 import androidx.glance.layout.padding
-import androidx.glance.template.FreeformTemplateData
-import androidx.glance.template.LocalTemplateMode
-import androidx.glance.template.TemplateMode
-import androidx.glance.template.TemplateText
-import androidx.glance.template.TextType
 import androidx.glance.unit.ColorProvider
 
 /**
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/GalleryTemplateData.kt b/glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateData.kt
similarity index 97%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/GalleryTemplateData.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateData.kt
index 381b851..efd0df6 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/GalleryTemplateData.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,11 +26,11 @@
  * @param galleryImageBlock The gallery block for a list of gallery images.
  */
 class GalleryTemplateData(
-    val header: HeaderBlock? = null,
     val mainTextBlock: TextBlock,
     val mainImageBlock: ImageBlock,
-    val mainActionBlock: ActionBlock? = null,
     val galleryImageBlock: ImageBlock,
+    val header: HeaderBlock? = null,
+    val mainActionBlock: ActionBlock? = null,
 ) {
     override fun hashCode(): Int {
         var result = mainTextBlock.hashCode()
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GalleryTemplateLayouts.kt b/glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateLayouts.kt
similarity index 93%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GalleryTemplateLayouts.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateLayouts.kt
index ca46041..8d66ce0 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GalleryTemplateLayouts.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/GalleryTemplateLayouts.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import android.os.Build
 import androidx.compose.runtime.Composable
@@ -27,7 +27,7 @@
 import androidx.glance.appwidget.lazy.GridCells
 import androidx.glance.appwidget.lazy.LazyVerticalGrid
 import androidx.glance.appwidget.lazy.itemsIndexed
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion.sizeMin
+import androidx.glance.template.GlanceTemplateAppWidget.Companion.sizeMin
 import androidx.glance.background
 import androidx.glance.layout.Alignment
 import androidx.glance.layout.Column
@@ -40,11 +40,6 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.padding
 import androidx.glance.layout.width
-import androidx.glance.template.AspectRatio
-import androidx.glance.template.GalleryTemplateData
-import androidx.glance.template.ImageSize
-import androidx.glance.template.LocalTemplateMode
-import androidx.glance.template.TemplateMode
 import kotlin.math.ceil
 import kotlin.math.pow
 import kotlin.math.roundToInt
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt b/glance/glance-template/src/main/java/androidx/glance/template/GlanceAppWidgetTemplates.kt
similarity index 94%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/GlanceAppWidgetTemplates.kt
index 8a297dbf..d5804bd 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/GlanceAppWidgetTemplates.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.unit.Dp
@@ -37,17 +37,6 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.size
 import androidx.glance.layout.width
-import androidx.glance.template.ActionBlock
-import androidx.glance.template.HeaderBlock
-import androidx.glance.template.ImageBlock
-import androidx.glance.template.ImageSize
-import androidx.glance.template.TemplateButton
-import androidx.glance.template.TemplateImageButton
-import androidx.glance.template.TemplateImageWithDescription
-import androidx.glance.template.TemplateText
-import androidx.glance.template.TemplateTextButton
-import androidx.glance.template.TextBlock
-import androidx.glance.template.TextType
 import androidx.glance.text.Text
 import androidx.glance.text.TextStyle
 
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/GlanceTemplate.kt b/glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplate.kt
similarity index 99%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/GlanceTemplate.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplate.kt
index c5503e2c..12fb0b5 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/GlanceTemplate.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplate.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt b/glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplateAppWidget.kt
similarity index 94%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplateAppWidget.kt
index 7774bcb..aedd8f4 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/GlanceTemplateAppWidget.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import android.content.Context
 import androidx.compose.runtime.Composable
@@ -30,8 +30,6 @@
 import androidx.glance.appwidget.provideContent
 import androidx.glance.state.GlanceStateDefinition
 import androidx.glance.state.PreferencesGlanceStateDefinition
-import androidx.glance.template.LocalTemplateMode
-import androidx.glance.template.TemplateMode
 
 /**
  * A [GlanceAppWidget] that provides template local values.
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/ListTemplateData.kt b/glance/glance-template/src/main/java/androidx/glance/template/ListTemplateData.kt
similarity index 98%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/ListTemplateData.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/ListTemplateData.kt
index e5659b8..1d0de24 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/ListTemplateData.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/ListTemplateData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/ListTemplateLayouts.kt b/glance/glance-template/src/main/java/androidx/glance/template/ListTemplateLayouts.kt
similarity index 92%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/ListTemplateLayouts.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/ListTemplateLayouts.kt
index b3fb6fa..f09f143 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/ListTemplateLayouts.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/ListTemplateLayouts.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 
 @file:GlanceComposable
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.unit.dp
@@ -35,11 +35,6 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.padding
 import androidx.glance.layout.width
-import androidx.glance.template.ImageBlock
-import androidx.glance.template.ListStyle
-import androidx.glance.template.ListTemplateData
-import androidx.glance.template.LocalTemplateMode
-import androidx.glance.template.TemplateMode
 
 /**
  * Composable layout for a list template app widget. The template is optimized to display a list of
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/SingleEntityTemplateData.kt b/glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateData.kt
similarity index 97%
rename from glance/glance/src/androidMain/kotlin/androidx/glance/template/SingleEntityTemplateData.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateData.kt
index a0a5308..649d0b6 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/SingleEntityTemplateData.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateData.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt b/glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateLayouts.kt
similarity index 90%
rename from glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
rename to glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateLayouts.kt
index f50c2ec..f954264 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
+++ b/glance/glance-template/src/main/java/androidx/glance/template/SingleEntityTemplateLayouts.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.glance.appwidget.template
+package androidx.glance.template
 
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.unit.dp
@@ -22,8 +22,8 @@
 import androidx.glance.GlanceTheme
 import androidx.glance.LocalSize
 import androidx.glance.appwidget.cornerRadius
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion.sizeMin
-import androidx.glance.appwidget.template.GlanceTemplateAppWidget.Companion.sizeS
+import androidx.glance.template.GlanceTemplateAppWidget.Companion.sizeMin
+import androidx.glance.template.GlanceTemplateAppWidget.Companion.sizeS
 import androidx.glance.background
 import androidx.glance.layout.Column
 import androidx.glance.layout.ContentScale
@@ -35,11 +35,6 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.padding
 import androidx.glance.layout.width
-import androidx.glance.template.LocalTemplateMode
-import androidx.glance.template.SingleEntityTemplateData
-import androidx.glance.template.TemplateMode
-import androidx.glance.template.TemplateText
-import androidx.glance.template.TextType
 
 // TODO: Define template layouts for other surfaces
 /**
@@ -154,7 +149,7 @@
         .fillMaxSize().padding(16.dp).cornerRadius(16.dp)
         .background(GlanceTheme.colors.primaryContainer)
     if (isImmersive && data.imageBlock?.images?.isNotEmpty() == true) {
-        val mainImage = data.imageBlock!!.images[0]
+        val mainImage = data.imageBlock.images[0]
         modifier = modifier.background(mainImage.image, ContentScale.Crop)
     }
 
diff --git a/glance/glance-wear-tiles/build.gradle b/glance/glance-wear-tiles/build.gradle
index a4b6f3b..bcfb47e 100644
--- a/glance/glance-wear-tiles/build.gradle
+++ b/glance/glance-wear-tiles/build.gradle
@@ -30,6 +30,7 @@
 dependencies {
 
     api(project(":glance:glance"))
+    api(project(":glance:glance-template"))
     api("androidx.compose.runtime:runtime:1.1.1")
     api("androidx.compose.ui:ui-graphics:1.1.1")
     api("androidx.compose.ui:ui-unit:1.1.1")
diff --git a/glance/glance/api/current.txt b/glance/glance/api/current.txt
index c9b546b..a0498de 100644
--- a/glance/glance/api/current.txt
+++ b/glance/glance/api/current.txt
@@ -437,233 +437,6 @@
 
 }
 
-package androidx.glance.template {
-
-  public final class ActionBlock {
-    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
-    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
-    method public int getType();
-    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
-    property public final int type;
-  }
-
-  @kotlin.jvm.JvmInline public final value class AspectRatio {
-    field public static final androidx.glance.template.AspectRatio.Companion Companion;
-  }
-
-  public static final class AspectRatio.Companion {
-    method public int getRatio16x9();
-    method public int getRatio1x1();
-    method public int getRatio2x3();
-    property public final int Ratio16x9;
-    property public final int Ratio1x1;
-    property public final int Ratio2x3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ButtonType {
-    field public static final androidx.glance.template.ButtonType.Companion Companion;
-  }
-
-  public static final class ButtonType.Companion {
-    method public int getFab();
-    method public int getIcon();
-    method public int getText();
-    method public int getTextIcon();
-    property public final int Fab;
-    property public final int Icon;
-    property public final int Text;
-    property public final int TextIcon;
-  }
-
-  public final class CompositionLocalsKt {
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
-  }
-
-  public final class FreeformTemplateData {
-    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
-    method public androidx.glance.template.TemplateImageButton? getActionIcon();
-    method public androidx.glance.unit.ColorProvider getBackgroundColor();
-    method public androidx.glance.ImageProvider? getBackgroundImage();
-    method public androidx.glance.template.TemplateText? getHeader();
-    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
-    method public androidx.glance.template.TemplateText? getSubtitle();
-    method public androidx.glance.template.TemplateText? getTitle();
-    property public final androidx.glance.template.TemplateImageButton? actionIcon;
-    property public final androidx.glance.unit.ColorProvider backgroundColor;
-    property public final androidx.glance.ImageProvider? backgroundImage;
-    property public final androidx.glance.template.TemplateText? header;
-    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
-    property public final androidx.glance.template.TemplateText? subtitle;
-    property public final androidx.glance.template.TemplateText? title;
-  }
-
-  public final class GalleryTemplateData {
-    ctor public GalleryTemplateData(optional androidx.glance.template.HeaderBlock? header, androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, optional androidx.glance.template.ActionBlock? mainActionBlock, androidx.glance.template.ImageBlock galleryImageBlock);
-    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
-    method public androidx.glance.template.HeaderBlock? getHeader();
-    method public androidx.glance.template.ActionBlock? getMainActionBlock();
-    method public androidx.glance.template.ImageBlock getMainImageBlock();
-    method public androidx.glance.template.TextBlock getMainTextBlock();
-    property public final androidx.glance.template.ImageBlock galleryImageBlock;
-    property public final androidx.glance.template.HeaderBlock? header;
-    property public final androidx.glance.template.ActionBlock? mainActionBlock;
-    property public final androidx.glance.template.ImageBlock mainImageBlock;
-    property public final androidx.glance.template.TextBlock mainTextBlock;
-  }
-
-  public final class HeaderBlock {
-    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
-    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
-    method public androidx.glance.template.TemplateText getText();
-    property public final androidx.glance.template.TemplateImageWithDescription? icon;
-    property public final androidx.glance.template.TemplateText text;
-  }
-
-  public final class ImageBlock {
-    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
-    method public int getAspectRatio();
-    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
-    method public int getPriority();
-    method public int getSize();
-    property public final int aspectRatio;
-    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
-    property public final int priority;
-    property public final int size;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ImageSize {
-    field public static final androidx.glance.template.ImageSize.Companion Companion;
-  }
-
-  public static final class ImageSize.Companion {
-    method public int getLarge();
-    method public int getMedium();
-    method public int getSmall();
-    method public int getUndefined();
-    property public final int Large;
-    property public final int Medium;
-    property public final int Small;
-    property public final int Undefined;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ListStyle {
-    field public static final androidx.glance.template.ListStyle.Companion Companion;
-  }
-
-  public static final class ListStyle.Companion {
-    method public int getBrief();
-    method public int getFull();
-    property public final int Brief;
-    property public final int Full;
-  }
-
-  public final class ListTemplateData {
-    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
-    method public int getListStyle();
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
-    property public final int listStyle;
-  }
-
-  public final class ListTemplateItem {
-    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock textBlock;
-  }
-
-  public final class SingleEntityTemplateData {
-    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock? getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock? textBlock;
-  }
-
-  public abstract sealed class TemplateButton {
-    method public final androidx.glance.action.Action getAction();
-    property public final androidx.glance.action.Action action;
-  }
-
-  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
-    method public androidx.glance.template.TemplateImageWithDescription getImage();
-    property public final androidx.glance.template.TemplateImageWithDescription image;
-  }
-
-  public final class TemplateImageWithDescription {
-    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
-    method public float getCornerRadius();
-    method public String getDescription();
-    method public androidx.glance.ImageProvider getImage();
-    property public final float cornerRadius;
-    property public final String description;
-    property public final androidx.glance.ImageProvider image;
-  }
-
-  public enum TemplateMode {
-    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.glance.template.TemplateMode[] values();
-    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
-    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
-    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
-  }
-
-  public final class TemplateText {
-    ctor public TemplateText(String text, optional int type);
-    method public String getText();
-    method public int getType();
-    property public final String text;
-    property public final int type;
-  }
-
-  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
-    method public String getText();
-    property public final String text;
-  }
-
-  public final class TextBlock {
-    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
-    method public int getPriority();
-    method public androidx.glance.template.TemplateText getText1();
-    method public androidx.glance.template.TemplateText? getText2();
-    method public androidx.glance.template.TemplateText? getText3();
-    property public final int priority;
-    property public final androidx.glance.template.TemplateText text1;
-    property public final androidx.glance.template.TemplateText? text2;
-    property public final androidx.glance.template.TemplateText? text3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class TextType {
-    field public static final androidx.glance.template.TextType.Companion Companion;
-  }
-
-  public static final class TextType.Companion {
-    method public int getBody();
-    method public int getDisplay();
-    method public int getHeadline();
-    method public int getLabel();
-    method public int getTitle();
-    property public final int Body;
-    property public final int Display;
-    property public final int Headline;
-    property public final int Label;
-    property public final int Title;
-  }
-
-}
-
 package androidx.glance.text {
 
   public final class FontFamily {
diff --git a/glance/glance/api/public_plus_experimental_current.txt b/glance/glance/api/public_plus_experimental_current.txt
index c9b546b..a0498de 100644
--- a/glance/glance/api/public_plus_experimental_current.txt
+++ b/glance/glance/api/public_plus_experimental_current.txt
@@ -437,233 +437,6 @@
 
 }
 
-package androidx.glance.template {
-
-  public final class ActionBlock {
-    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
-    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
-    method public int getType();
-    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
-    property public final int type;
-  }
-
-  @kotlin.jvm.JvmInline public final value class AspectRatio {
-    field public static final androidx.glance.template.AspectRatio.Companion Companion;
-  }
-
-  public static final class AspectRatio.Companion {
-    method public int getRatio16x9();
-    method public int getRatio1x1();
-    method public int getRatio2x3();
-    property public final int Ratio16x9;
-    property public final int Ratio1x1;
-    property public final int Ratio2x3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ButtonType {
-    field public static final androidx.glance.template.ButtonType.Companion Companion;
-  }
-
-  public static final class ButtonType.Companion {
-    method public int getFab();
-    method public int getIcon();
-    method public int getText();
-    method public int getTextIcon();
-    property public final int Fab;
-    property public final int Icon;
-    property public final int Text;
-    property public final int TextIcon;
-  }
-
-  public final class CompositionLocalsKt {
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
-  }
-
-  public final class FreeformTemplateData {
-    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
-    method public androidx.glance.template.TemplateImageButton? getActionIcon();
-    method public androidx.glance.unit.ColorProvider getBackgroundColor();
-    method public androidx.glance.ImageProvider? getBackgroundImage();
-    method public androidx.glance.template.TemplateText? getHeader();
-    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
-    method public androidx.glance.template.TemplateText? getSubtitle();
-    method public androidx.glance.template.TemplateText? getTitle();
-    property public final androidx.glance.template.TemplateImageButton? actionIcon;
-    property public final androidx.glance.unit.ColorProvider backgroundColor;
-    property public final androidx.glance.ImageProvider? backgroundImage;
-    property public final androidx.glance.template.TemplateText? header;
-    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
-    property public final androidx.glance.template.TemplateText? subtitle;
-    property public final androidx.glance.template.TemplateText? title;
-  }
-
-  public final class GalleryTemplateData {
-    ctor public GalleryTemplateData(optional androidx.glance.template.HeaderBlock? header, androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, optional androidx.glance.template.ActionBlock? mainActionBlock, androidx.glance.template.ImageBlock galleryImageBlock);
-    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
-    method public androidx.glance.template.HeaderBlock? getHeader();
-    method public androidx.glance.template.ActionBlock? getMainActionBlock();
-    method public androidx.glance.template.ImageBlock getMainImageBlock();
-    method public androidx.glance.template.TextBlock getMainTextBlock();
-    property public final androidx.glance.template.ImageBlock galleryImageBlock;
-    property public final androidx.glance.template.HeaderBlock? header;
-    property public final androidx.glance.template.ActionBlock? mainActionBlock;
-    property public final androidx.glance.template.ImageBlock mainImageBlock;
-    property public final androidx.glance.template.TextBlock mainTextBlock;
-  }
-
-  public final class HeaderBlock {
-    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
-    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
-    method public androidx.glance.template.TemplateText getText();
-    property public final androidx.glance.template.TemplateImageWithDescription? icon;
-    property public final androidx.glance.template.TemplateText text;
-  }
-
-  public final class ImageBlock {
-    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
-    method public int getAspectRatio();
-    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
-    method public int getPriority();
-    method public int getSize();
-    property public final int aspectRatio;
-    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
-    property public final int priority;
-    property public final int size;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ImageSize {
-    field public static final androidx.glance.template.ImageSize.Companion Companion;
-  }
-
-  public static final class ImageSize.Companion {
-    method public int getLarge();
-    method public int getMedium();
-    method public int getSmall();
-    method public int getUndefined();
-    property public final int Large;
-    property public final int Medium;
-    property public final int Small;
-    property public final int Undefined;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ListStyle {
-    field public static final androidx.glance.template.ListStyle.Companion Companion;
-  }
-
-  public static final class ListStyle.Companion {
-    method public int getBrief();
-    method public int getFull();
-    property public final int Brief;
-    property public final int Full;
-  }
-
-  public final class ListTemplateData {
-    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
-    method public int getListStyle();
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
-    property public final int listStyle;
-  }
-
-  public final class ListTemplateItem {
-    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock textBlock;
-  }
-
-  public final class SingleEntityTemplateData {
-    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock? getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock? textBlock;
-  }
-
-  public abstract sealed class TemplateButton {
-    method public final androidx.glance.action.Action getAction();
-    property public final androidx.glance.action.Action action;
-  }
-
-  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
-    method public androidx.glance.template.TemplateImageWithDescription getImage();
-    property public final androidx.glance.template.TemplateImageWithDescription image;
-  }
-
-  public final class TemplateImageWithDescription {
-    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
-    method public float getCornerRadius();
-    method public String getDescription();
-    method public androidx.glance.ImageProvider getImage();
-    property public final float cornerRadius;
-    property public final String description;
-    property public final androidx.glance.ImageProvider image;
-  }
-
-  public enum TemplateMode {
-    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.glance.template.TemplateMode[] values();
-    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
-    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
-    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
-  }
-
-  public final class TemplateText {
-    ctor public TemplateText(String text, optional int type);
-    method public String getText();
-    method public int getType();
-    property public final String text;
-    property public final int type;
-  }
-
-  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
-    method public String getText();
-    property public final String text;
-  }
-
-  public final class TextBlock {
-    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
-    method public int getPriority();
-    method public androidx.glance.template.TemplateText getText1();
-    method public androidx.glance.template.TemplateText? getText2();
-    method public androidx.glance.template.TemplateText? getText3();
-    property public final int priority;
-    property public final androidx.glance.template.TemplateText text1;
-    property public final androidx.glance.template.TemplateText? text2;
-    property public final androidx.glance.template.TemplateText? text3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class TextType {
-    field public static final androidx.glance.template.TextType.Companion Companion;
-  }
-
-  public static final class TextType.Companion {
-    method public int getBody();
-    method public int getDisplay();
-    method public int getHeadline();
-    method public int getLabel();
-    method public int getTitle();
-    property public final int Body;
-    property public final int Display;
-    property public final int Headline;
-    property public final int Label;
-    property public final int Title;
-  }
-
-}
-
 package androidx.glance.text {
 
   public final class FontFamily {
diff --git a/glance/glance/api/restricted_current.txt b/glance/glance/api/restricted_current.txt
index c9b546b..a0498de 100644
--- a/glance/glance/api/restricted_current.txt
+++ b/glance/glance/api/restricted_current.txt
@@ -437,233 +437,6 @@
 
 }
 
-package androidx.glance.template {
-
-  public final class ActionBlock {
-    ctor public ActionBlock(optional java.util.List<? extends androidx.glance.template.TemplateButton> actionButtons, optional int type);
-    method public java.util.List<androidx.glance.template.TemplateButton> getActionButtons();
-    method public int getType();
-    property public final java.util.List<androidx.glance.template.TemplateButton> actionButtons;
-    property public final int type;
-  }
-
-  @kotlin.jvm.JvmInline public final value class AspectRatio {
-    field public static final androidx.glance.template.AspectRatio.Companion Companion;
-  }
-
-  public static final class AspectRatio.Companion {
-    method public int getRatio16x9();
-    method public int getRatio1x1();
-    method public int getRatio2x3();
-    property public final int Ratio16x9;
-    property public final int Ratio1x1;
-    property public final int Ratio2x3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ButtonType {
-    field public static final androidx.glance.template.ButtonType.Companion Companion;
-  }
-
-  public static final class ButtonType.Companion {
-    method public int getFab();
-    method public int getIcon();
-    method public int getText();
-    method public int getTextIcon();
-    property public final int Fab;
-    property public final int Icon;
-    property public final int Text;
-    property public final int TextIcon;
-  }
-
-  public final class CompositionLocalsKt {
-    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
-    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
-  }
-
-  public final class FreeformTemplateData {
-    ctor public FreeformTemplateData(androidx.glance.unit.ColorProvider backgroundColor, androidx.glance.template.TemplateImageWithDescription headerIcon, androidx.glance.template.TemplateImageButton? actionIcon, optional androidx.glance.template.TemplateText? header, optional androidx.glance.template.TemplateText? title, optional androidx.glance.template.TemplateText? subtitle, optional androidx.glance.ImageProvider? backgroundImage);
-    method public androidx.glance.template.TemplateImageButton? getActionIcon();
-    method public androidx.glance.unit.ColorProvider getBackgroundColor();
-    method public androidx.glance.ImageProvider? getBackgroundImage();
-    method public androidx.glance.template.TemplateText? getHeader();
-    method public androidx.glance.template.TemplateImageWithDescription getHeaderIcon();
-    method public androidx.glance.template.TemplateText? getSubtitle();
-    method public androidx.glance.template.TemplateText? getTitle();
-    property public final androidx.glance.template.TemplateImageButton? actionIcon;
-    property public final androidx.glance.unit.ColorProvider backgroundColor;
-    property public final androidx.glance.ImageProvider? backgroundImage;
-    property public final androidx.glance.template.TemplateText? header;
-    property public final androidx.glance.template.TemplateImageWithDescription headerIcon;
-    property public final androidx.glance.template.TemplateText? subtitle;
-    property public final androidx.glance.template.TemplateText? title;
-  }
-
-  public final class GalleryTemplateData {
-    ctor public GalleryTemplateData(optional androidx.glance.template.HeaderBlock? header, androidx.glance.template.TextBlock mainTextBlock, androidx.glance.template.ImageBlock mainImageBlock, optional androidx.glance.template.ActionBlock? mainActionBlock, androidx.glance.template.ImageBlock galleryImageBlock);
-    method public androidx.glance.template.ImageBlock getGalleryImageBlock();
-    method public androidx.glance.template.HeaderBlock? getHeader();
-    method public androidx.glance.template.ActionBlock? getMainActionBlock();
-    method public androidx.glance.template.ImageBlock getMainImageBlock();
-    method public androidx.glance.template.TextBlock getMainTextBlock();
-    property public final androidx.glance.template.ImageBlock galleryImageBlock;
-    property public final androidx.glance.template.HeaderBlock? header;
-    property public final androidx.glance.template.ActionBlock? mainActionBlock;
-    property public final androidx.glance.template.ImageBlock mainImageBlock;
-    property public final androidx.glance.template.TextBlock mainTextBlock;
-  }
-
-  public final class HeaderBlock {
-    ctor public HeaderBlock(androidx.glance.template.TemplateText text, optional androidx.glance.template.TemplateImageWithDescription? icon);
-    method public androidx.glance.template.TemplateImageWithDescription? getIcon();
-    method public androidx.glance.template.TemplateText getText();
-    property public final androidx.glance.template.TemplateImageWithDescription? icon;
-    property public final androidx.glance.template.TemplateText text;
-  }
-
-  public final class ImageBlock {
-    ctor public ImageBlock(optional java.util.List<androidx.glance.template.TemplateImageWithDescription> images, optional int aspectRatio, optional int size, optional @IntRange(from=0L) int priority);
-    method public int getAspectRatio();
-    method public java.util.List<androidx.glance.template.TemplateImageWithDescription> getImages();
-    method public int getPriority();
-    method public int getSize();
-    property public final int aspectRatio;
-    property public final java.util.List<androidx.glance.template.TemplateImageWithDescription> images;
-    property public final int priority;
-    property public final int size;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ImageSize {
-    field public static final androidx.glance.template.ImageSize.Companion Companion;
-  }
-
-  public static final class ImageSize.Companion {
-    method public int getLarge();
-    method public int getMedium();
-    method public int getSmall();
-    method public int getUndefined();
-    property public final int Large;
-    property public final int Medium;
-    property public final int Small;
-    property public final int Undefined;
-  }
-
-  @kotlin.jvm.JvmInline public final value class ListStyle {
-    field public static final androidx.glance.template.ListStyle.Companion Companion;
-  }
-
-  public static final class ListStyle.Companion {
-    method public int getBrief();
-    method public int getFull();
-    property public final int Brief;
-    property public final int Full;
-  }
-
-  public final class ListTemplateData {
-    ctor public ListTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional java.util.List<androidx.glance.template.ListTemplateItem> listContent, optional int listStyle);
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public java.util.List<androidx.glance.template.ListTemplateItem> getListContent();
-    method public int getListStyle();
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final java.util.List<androidx.glance.template.ListTemplateItem> listContent;
-    property public final int listStyle;
-  }
-
-  public final class ListTemplateItem {
-    ctor public ListTemplateItem(androidx.glance.template.TextBlock textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock textBlock;
-  }
-
-  public final class SingleEntityTemplateData {
-    ctor public SingleEntityTemplateData(optional androidx.glance.template.HeaderBlock? headerBlock, optional androidx.glance.template.TextBlock? textBlock, optional androidx.glance.template.ImageBlock? imageBlock, optional androidx.glance.template.ActionBlock? actionBlock);
-    method public androidx.glance.template.ActionBlock? getActionBlock();
-    method public androidx.glance.template.HeaderBlock? getHeaderBlock();
-    method public androidx.glance.template.ImageBlock? getImageBlock();
-    method public androidx.glance.template.TextBlock? getTextBlock();
-    property public final androidx.glance.template.ActionBlock? actionBlock;
-    property public final androidx.glance.template.HeaderBlock? headerBlock;
-    property public final androidx.glance.template.ImageBlock? imageBlock;
-    property public final androidx.glance.template.TextBlock? textBlock;
-  }
-
-  public abstract sealed class TemplateButton {
-    method public final androidx.glance.action.Action getAction();
-    property public final androidx.glance.action.Action action;
-  }
-
-  public final class TemplateImageButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateImageButton(androidx.glance.action.Action action, androidx.glance.template.TemplateImageWithDescription image);
-    method public androidx.glance.template.TemplateImageWithDescription getImage();
-    property public final androidx.glance.template.TemplateImageWithDescription image;
-  }
-
-  public final class TemplateImageWithDescription {
-    ctor public TemplateImageWithDescription(androidx.glance.ImageProvider image, String description, optional float cornerRadius);
-    method public float getCornerRadius();
-    method public String getDescription();
-    method public androidx.glance.ImageProvider getImage();
-    property public final float cornerRadius;
-    property public final String description;
-    property public final androidx.glance.ImageProvider image;
-  }
-
-  public enum TemplateMode {
-    method public static androidx.glance.template.TemplateMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.glance.template.TemplateMode[] values();
-    enum_constant public static final androidx.glance.template.TemplateMode Collapsed;
-    enum_constant public static final androidx.glance.template.TemplateMode Horizontal;
-    enum_constant public static final androidx.glance.template.TemplateMode Vertical;
-  }
-
-  public final class TemplateText {
-    ctor public TemplateText(String text, optional int type);
-    method public String getText();
-    method public int getType();
-    property public final String text;
-    property public final int type;
-  }
-
-  public final class TemplateTextButton extends androidx.glance.template.TemplateButton {
-    ctor public TemplateTextButton(androidx.glance.action.Action action, String text);
-    method public String getText();
-    property public final String text;
-  }
-
-  public final class TextBlock {
-    ctor public TextBlock(androidx.glance.template.TemplateText text1, optional androidx.glance.template.TemplateText? text2, optional androidx.glance.template.TemplateText? text3, optional @IntRange(from=0L) int priority);
-    method public int getPriority();
-    method public androidx.glance.template.TemplateText getText1();
-    method public androidx.glance.template.TemplateText? getText2();
-    method public androidx.glance.template.TemplateText? getText3();
-    property public final int priority;
-    property public final androidx.glance.template.TemplateText text1;
-    property public final androidx.glance.template.TemplateText? text2;
-    property public final androidx.glance.template.TemplateText? text3;
-  }
-
-  @kotlin.jvm.JvmInline public final value class TextType {
-    field public static final androidx.glance.template.TextType.Companion Companion;
-  }
-
-  public static final class TextType.Companion {
-    method public int getBody();
-    method public int getDisplay();
-    method public int getHeadline();
-    method public int getLabel();
-    method public int getTitle();
-    property public final int Body;
-    property public final int Display;
-    property public final int Headline;
-    property public final int Label;
-    property public final int Title;
-  }
-
-}
-
 package androidx.glance.text {
 
   public final class FontFamily {
diff --git a/gradle.properties b/gradle.properties
index bc33a1a..47646f4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -28,7 +28,7 @@
 androidx.writeVersionedApiFiles=true
 
 # Run the CheckAarMetadata task
-androidx.checkAarMetadata=true
+android.experimental.disableCompileSdkChecks=false
 
 # Do restrict compileSdkPreview usage
 androidx.allowCustomCompileSdk=false
@@ -70,7 +70,9 @@
 kotlin.mpp.androidGradlePluginCompatibility.nowarn=true
 # Until we get a newer AGP which doesn't do this
 kotlin.options.suppressFreeCompilerArgsModificationWarning=true
+# b/275795136
+ksp.incremental=false
 
 # Properties we often want to toggle
-# ksp.version.check=false
+ksp.version.check=false
 # androidx.compose.multiplatformEnabled=true
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7505dc8..a69e504 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -14,12 +14,12 @@
 androidGradlePluginMin = "7.0.4"
 androidLintMin = "30.0.4"
 androidLintMinCompose = "30.0.0"
-androidxTestRunner = "1.5.2"
-androidxTestRules = "1.5.0"
-androidxTestMonitor = "1.6.1"
-androidxTestCore = "1.5.0"
-androidxTestExtJunit = "1.1.5"
-androidxTestExtTruth = "1.5.0"
+androidxTestRunner = "1.6.0-alpha01"
+androidxTestRules = "1.6.0-alpha01"
+androidxTestMonitor = "1.7.0-alpha01"
+androidxTestCore = "1.6.0-alpha01"
+androidxTestExtJunit = "1.2.0-alpha01"
+androidxTestExtTruth = "1.6.0-alpha01"
 atomicFu = "0.17.0"
 autoService = "1.0-rc6"
 autoValue = "1.6.3"
@@ -29,20 +29,20 @@
 dagger = "2.44"
 dexmaker = "2.28.3"
 dokka = "1.8.10-dev-203"
-espresso = "3.5.1"
-espressoDevice = "1.0.0-alpha03"
+espresso = "3.6.0-alpha01"
+espressoDevice = "1.0.0-alpha04"
 grpc = "1.52.0"
 guavaJre = "31.1-jre"
 hilt = "2.44"
 incap = "0.2"
 jcodec = "0.2.5"
-kotlin = "1.8.10"
+kotlin = "1.8.20"
 kotlinBenchmark = "0.4.7"
-kotlinNative = "1.8.10"
+kotlinNative = "1.8.20"
 kotlinCompileTesting = "1.4.9"
 kotlinCoroutines = "1.6.4"
 kotlinSerialization = "1.3.3"
-ksp = "1.8.10-1.0.9"
+ksp = "1.8.20-1.0.10"
 ktlint = "0.46.0-20220520.192227-74"
 leakcanary = "2.8.1"
 media3 = "1.0.0-beta03"
@@ -55,7 +55,7 @@
 skiko = "0.7.7"
 sqldelight = "1.3.0"
 retrofit = "2.7.2"
-wire = "4.4.1"
+wire = "4.5.1"
 
 [libraries]
 agpTestingPlatformCoreProto =  { module = "com.google.testing.platform:core-proto", version = "0.0.8-alpha08" }
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 309ad72..0150fc4 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -423,19 +423,19 @@
       </trusted-keys>
    </configuration>
    <components>
-      <component group="" name="kotlin-native-prebuilt-linux-x86_64" version="1.8.10">
-         <artifact name="kotlin-native-prebuilt-linux-x86_64-1.8.10.tar.gz">
-            <sha256 value="7c031ecc225cacc96c9479be28249d57226ff10a1d9ad78340ed6efffd06bdf5" origin="Hand-built using sha256sum kotlin-native-prebuilt-linux-x86_64-1.8.10.tar.gz" reason="Artifact is not signed"/>
+      <component group="" name="kotlin-native-prebuilt-linux-x86_64" version="1.8.20">
+         <artifact name="kotlin-native-prebuilt-linux-x86_64-1.8.20.tar.gz">
+            <sha256 value="39a5933464cb4d5ae8b5c309c2e2c1641f0de9b12fae164114c6f98b2204fd8b" origin="Hand-built using sha256sum kotlin-native-prebuilt-linux-x86_64-1.8.20.tar.gz" reason="Artifact is not signed"/>
          </artifact>
       </component>
-      <component group="" name="kotlin-native-prebuilt-macos-aarch64" version="1.8.10">
-         <artifact name="kotlin-native-prebuilt-macos-aarch64-1.8.10.tar.gz">
-            <sha256 value="b15d176c8b88ee6d4bc8017e17462222081dca2e97347fd9eecd554c5839a819" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-aarch64-1.8.10.tar.gz"/>
+      <component group="" name="kotlin-native-prebuilt-macos-aarch64" version="1.8.20">
+         <artifact name="kotlin-native-prebuilt-macos-aarch64-1.8.20.tar.gz">
+            <sha256 value="b5bf0147a7d9497174a4fbafd0dffb1c519abd341b84eb17e621fc861ec7aea4" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-aarch64-1.8.20.tar.gz"/>
          </artifact>
       </component>
-      <component group="" name="kotlin-native-prebuilt-macos-x86_64" version="1.8.10">
-         <artifact name="kotlin-native-prebuilt-macos-x86_64-1.8.10.tar.gz">
-            <sha256 value="8a31a27a776ba55974936b897be76edca1cf871d9ae75537e593a7f1b83380e9" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-x86_64-1.8.10.tar.gz"/>
+      <component group="" name="kotlin-native-prebuilt-macos-x86_64" version="1.8.20">
+         <artifact name="kotlin-native-prebuilt-macos-x86_64-1.8.20.tar.gz">
+            <sha256 value="0327fa1c7cc7defbb1aa7b6101e9a71fc182c3b6a9d1889e8aaf4d716200ffa8" origin="Hand-built using sha256sum kotlin-native-prebuilt-macos-x86_64-1.8.20.tar.gz"/>
          </artifact>
       </component>
       <component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.12.7.1">
@@ -476,6 +476,14 @@
             <sha256 value="d46777ad3ea8bca73491b2e02fc85b3664486abf5314cc4dc6740908bd855330" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
+      <component group="com.google.android.apps.common.testing.accessibility.framework" name="accessibility-test-framework" version="3.1">
+         <artifact name="accessibility-test-framework-3.1.aar">
+            <sha256 value="e641e2a2c7287afd41b85310dd8f1344a8668034bbbfc4b02f58a48fd9c05ec7" origin="Generated by Gradle" reason="Artifact is not signed"/>
+         </artifact>
+         <artifact name="accessibility-test-framework-3.1.pom">
+            <sha256 value="80567228cdbd44d61e5320cd090883de7232dbc1ed7ebf5ab5c9810c11cd67e0" origin="Generated by Gradle" reason="Artifact is not signed"/>
+         </artifact>
+      </component>
       <component group="com.google.android.apps.common.testing.accessibility.framework" name="accessibility-test-framework" version="3.1.2">
          <artifact name="accessibility-test-framework-3.1.2.aar">
             <sha256 value="9b586dc8eeeb4f601038e23ef8ffd6a1deeca1163276d02797b0d2b8f9764b62" origin="Generated by Gradle" reason="Artifact is not signed"/>
diff --git a/graphics/OWNERS b/graphics/OWNERS
index 9ba9c32..795eb1c 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -1,4 +1,6 @@
 # Bug component: 1137062
 [email protected]
[email protected]
[email protected]
 [email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt
index c50882c..ef658d4 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt
@@ -47,6 +47,9 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     @Test
     fun testFrontBufferedLayerRender() {
+        if (!isSupported()) {
+            return
+        }
         val renderLatch = CountDownLatch(1)
         val callbacks = object : CanvasFrontBufferedRenderer.Callback<Any> {
             override fun onDrawFrontBufferedLayer(
@@ -120,6 +123,9 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     @Test
     fun testMultiBufferedLayerRender() {
+        if (!isSupported()) {
+            return
+        }
         val renderLatch = CountDownLatch(1)
         val callbacks = object : CanvasFrontBufferedRenderer.Callback<Any> {
 
@@ -316,6 +322,9 @@
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
     @Test
     fun testCancelFrontBufferLayerRender() {
+        if (!isSupported()) {
+            return
+        }
         val squareSize = 100f
         val renderLatch = CountDownLatch(1)
         val callbacks = object : CanvasFrontBufferedRenderer.Callback<Int> {
@@ -500,6 +509,9 @@
 
     @RequiresApi(Build.VERSION_CODES.Q)
     fun parentLayerRotationTest(rotation: Int) {
+        if (!isSupported()) {
+            return
+        }
         var surfaceView: SurfaceView? = null
         val renderLatch = CountDownLatch(1)
         val topLeftColor = Color.RED
@@ -622,4 +634,11 @@
             Assert.fail("CanvasFrontBufferedRenderer is not initialized")
         }
     }
+
+    private fun isSupported(): Boolean =
+        // See "b/277225133" these tests pass on cuttlefish + other devices but fail for some reason
+        // FTL configured API level 33 emulator instances
+        // Additionally some cuttlefish instances don't support rotation based testing (b/277764242)
+        !(Build.MODEL.contains("gphone") && Build.VERSION.SDK_INT == 33) &&
+            !(Build.MODEL.contains("Cuttlefish") && Build.VERSION.SDK_INT == 30)
 }
\ No newline at end of file
diff --git a/graphics/graphics-shapes/api/current.txt b/graphics/graphics-shapes/api/current.txt
index 9455b94..8c1144b 100644
--- a/graphics/graphics-shapes/api/current.txt
+++ b/graphics/graphics-shapes/api/current.txt
@@ -81,8 +81,6 @@
   }
 
   public final class RoundedPolygon {
-    ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional android.graphics.PointF? center);
-    ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center);
     ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF? center);
     ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
     ctor public RoundedPolygon(androidx.graphics.shapes.RoundedPolygon source);
@@ -104,12 +102,13 @@
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius, optional android.graphics.PointF center);
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius);
     method public static androidx.graphics.shapes.RoundedPolygon Circle();
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius);
   }
 
 }
diff --git a/graphics/graphics-shapes/api/public_plus_experimental_current.txt b/graphics/graphics-shapes/api/public_plus_experimental_current.txt
index 9455b94..8c1144b 100644
--- a/graphics/graphics-shapes/api/public_plus_experimental_current.txt
+++ b/graphics/graphics-shapes/api/public_plus_experimental_current.txt
@@ -81,8 +81,6 @@
   }
 
   public final class RoundedPolygon {
-    ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional android.graphics.PointF? center);
-    ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center);
     ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF? center);
     ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
     ctor public RoundedPolygon(androidx.graphics.shapes.RoundedPolygon source);
@@ -104,12 +102,13 @@
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius, optional android.graphics.PointF center);
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius);
     method public static androidx.graphics.shapes.RoundedPolygon Circle();
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius);
   }
 
 }
diff --git a/graphics/graphics-shapes/api/restricted_current.txt b/graphics/graphics-shapes/api/restricted_current.txt
index 9455b94..8c1144b 100644
--- a/graphics/graphics-shapes/api/restricted_current.txt
+++ b/graphics/graphics-shapes/api/restricted_current.txt
@@ -81,8 +81,6 @@
   }
 
   public final class RoundedPolygon {
-    ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional android.graphics.PointF? center);
-    ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center);
     ctor public RoundedPolygon(java.util.List<? extends android.graphics.PointF> vertices, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF? center);
     ctor public RoundedPolygon(int numVertices, optional float radius, optional android.graphics.PointF center, optional androidx.graphics.shapes.CornerRounding rounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
     ctor public RoundedPolygon(androidx.graphics.shapes.RoundedPolygon source);
@@ -104,12 +102,13 @@
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius, optional android.graphics.PointF center);
     method public static androidx.graphics.shapes.RoundedPolygon Circle(optional float radius);
     method public static androidx.graphics.shapes.RoundedPolygon Circle();
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius, optional androidx.graphics.shapes.CornerRounding rounding);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio, optional float radius);
-    method public static androidx.graphics.shapes.RoundedPolygon Star(int numOuterVertices, @FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float innerRadiusRatio);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding, optional android.graphics.PointF center);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding, optional java.util.List<androidx.graphics.shapes.CornerRounding>? perVertexRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding, optional androidx.graphics.shapes.CornerRounding? innerRounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius, optional androidx.graphics.shapes.CornerRounding rounding);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius, optional float innerRadius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius, optional float radius);
+    method public static androidx.graphics.shapes.RoundedPolygon Star(int numVerticesPerRadius);
   }
 
 }
diff --git a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
index c715b1e..610fa3e 100644
--- a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
+++ b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
@@ -65,8 +65,8 @@
         assertInBounds(manualSquare.toCubicShape(), min, max)
 
         val offset = PointF(1f, 2f)
-        val manualSquareOffset =
-            RoundedPolygon(listOf(p0 + offset, p1 + offset, p2 + offset, p3 + offset), offset)
+        val manualSquareOffset = RoundedPolygon(
+            vertices = listOf(p0 + offset, p1 + offset, p2 + offset, p3 + offset), center = offset)
         min = PointF(0f, 1f)
         max = PointF(2f, 3f)
         assertInBounds(manualSquareOffset.toCubicShape(), min, max)
diff --git a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedRoundedPolygonTest.kt b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedPolygonTest.kt
similarity index 98%
rename from graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedRoundedPolygonTest.kt
rename to graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedPolygonTest.kt
index 46f71be..11925c6 100644
--- a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedRoundedPolygonTest.kt
+++ b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/RoundedPolygonTest.kt
@@ -23,7 +23,7 @@
 import org.junit.Test
 
 @SmallTest
-class RoundedRoundedPolygonTest {
+class RoundedPolygonTest {
 
     val rounding = CornerRounding(.1f)
     val perVtxRounded = listOf<CornerRounding>(rounding, rounding, rounding, rounding)
diff --git a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/ShapesTest.kt b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/ShapesTest.kt
index 05f1f8e9..83755ae 100644
--- a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/ShapesTest.kt
+++ b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/ShapesTest.kt
@@ -108,24 +108,27 @@
      */
     @Test
     fun starTest() {
-        var star = Star(4, innerRadiusRatio = .5f)
+        var star = Star(4, innerRadius = .5f)
         var shape = star.toCubicShape()
+        var radius = 1f
+        var innerRadius = .5f
         for (cubic in shape.cubics) {
-            assertCubicOnRadii(cubic, 1f, .5f)
+            assertCubicOnRadii(cubic, radius, innerRadius)
         }
 
         val center = PointF(1f, 2f)
-        star = Star(4, innerRadiusRatio = .5f, center = center)
+        star = Star(4, innerRadius = innerRadius, center = center)
         shape = star.toCubicShape()
         for (cubic in shape.cubics) {
-            assertCubicOnRadii(cubic, 1f, .5f, center)
+            assertCubicOnRadii(cubic, radius, innerRadius, center)
         }
 
-        val radius = 4f
-        star = Star(4, radius = radius, innerRadiusRatio = .5f)
+        radius = 4f
+        innerRadius = 2f
+        star = Star(4, radius, innerRadius)
         shape = star.toCubicShape()
         for (cubic in shape.cubics) {
-            assertCubicOnRadii(cubic, radius, .5f * radius)
+            assertCubicOnRadii(cubic, radius, innerRadius)
         }
     }
 
@@ -136,24 +139,28 @@
         val perVtxRounded = listOf<CornerRounding>(rounding, innerRounding, rounding, innerRounding,
             rounding, innerRounding, rounding, innerRounding)
 
-        var star = Star(4, innerRadiusRatio = .5f, rounding = rounding)
+        var star = Star(4, innerRadius = .5f, rounding = rounding)
         val min = PointF(-1f, -1f)
         val max = PointF(1f, 1f)
         assertInBounds(star.toCubicShape(), min, max)
 
-        star = Star(4, innerRadiusRatio = .5f, innerRounding = innerRounding)
+        star = Star(4, innerRadius = .5f, innerRounding = innerRounding)
         assertInBounds(star.toCubicShape(), min, max)
 
-        star = Star(4, innerRadiusRatio = .5f, rounding = rounding,
-            innerRounding = innerRounding)
+        star = Star(
+            4, innerRadius = .5f, rounding = rounding,
+            innerRounding = innerRounding
+        )
         assertInBounds(star.toCubicShape(), min, max)
 
-        star = Star(4, innerRadiusRatio = .5f, perVertexRounding = perVtxRounded)
+        star = Star(4, innerRadius = .5f, perVertexRounding = perVtxRounded)
         assertInBounds(star.toCubicShape(), min, max)
 
         assertThrows(IllegalArgumentException::class.java) {
-            star = Star(6, innerRadiusRatio = .5f,
-                perVertexRounding = perVtxRounded)
+            star = Star(
+                6, innerRadius = .5f,
+                perVertexRounding = perVtxRounded
+            )
         }
     }
 }
\ No newline at end of file
diff --git a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/RoundedPolygon.kt b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/RoundedPolygon.kt
index 60061ce..69a19c6 100644
--- a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/RoundedPolygon.kt
+++ b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/RoundedPolygon.kt
@@ -78,34 +78,6 @@
      * Constructs a RoundedPolygon object from a given list of vertices, with optional
      * corner-rounding parameters for all corners or per-corner.
      *
-     * @param vertices The list of vertices in this polygon. This should be an ordered list
-     * (with the outline of the shape going from each vertex to the next in order of this
-     * list), otherwise the results will be undefined.
-     * @param center An optionally declared center of the polygon. If null or not supplied, this
-     * will be calculated based on the supplied vertices.
-     */
-    constructor(vertices: List<PointF>, center: PointF? = null) :
-        this(vertices, rounding = CornerRounding.Unrounded, perVertexRounding = null, center)
-
-    /**
-     * This constructor takes the number of vertices in the resulting polygon. These vertices are
-     * positioned on a virtual circle around a given center with each vertex positioned [radius]
-     * distance from that center, equally spaced (with equal angles between them).
-     *
-     * @param numVertices The number of vertices in this polygon.
-     * @param radius The radius of the polygon, in pixels. This radius determines the
-     * initial size of the object, which can be resized later by setting
-     * a [transform matrix][transform].
-     * @param center The center of the polygon, around which all vertices will be placed. The
-     * default center is at (0,0).
-     */
-    constructor(numVertices: Int, radius: Float = 1f, center: PointF = PointF(0f, 0f)) :
-        this(numVertices, radius = radius, center = center, rounding = CornerRounding.Unrounded)
-
-    /**
-     * Constructs a RoundedPolygon object from a given list of vertices, with optional
-     * corner-rounding parameters for all corners or per-corner.
-     *
      * A RoundedPolygon without any rounding parameters is equivalent to a [RoundedPolygon] constructed
      * with the same [vertices] and [center].
      *
diff --git a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Shapes.kt b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Shapes.kt
index 9f8a5ec..4e8898d 100644
--- a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Shapes.kt
+++ b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Shapes.kt
@@ -17,7 +17,6 @@
 package androidx.graphics.shapes
 
 import android.graphics.PointF
-import androidx.annotation.FloatRange
 
 private const val Sqrt2 = 1.41421356f
 
@@ -36,42 +35,63 @@
 
 /**
  * Creates a star polygon, which is like a regular polygon except every other vertex is
- * on either an inner or outer radius. The two radii are specified in the constructor by
- * providing the [innerRadiusRatio], which is a value representing the proportion (from
- * 0 to 1, non-inclusive) of the inner radius compared to the outer one.
- * @throws IllegalArgumentException if radius ratio not in [0,1]
+ * on either an inner or outer radius. The two radii specified in the constructor must both
+ * both nonzero. If the radii are equal, the result will be a regular (not star) polygon with twice
+ * the number of vertices specified in [numVerticesPerRadius].
+ *
+ * @param numVerticesPerRadius The number of vertices along each of the two radii.
+ * @param radius Outer radius for this star shape, must be greater than 0. Default value is 1.
+ * @param innerRadius Inner radius for this star shape, must be greater than 0 and less
+ * than or equal to [radius]. Note that equal radii would be the same as creating a
+ * [RoundedPolygon] directly, but with 2 * [numVerticesPerRadius] vertices. Default value is .5.
+ * @param rounding The [CornerRounding] properties of every vertex. If some vertices should
+ * have different rounding properties, then use [perVertexRounding] instead. The default
+ * rounding value is [CornerRounding.Unrounded], meaning that the polygon will use the vertices
+ * themselves in the final shape and not curves rounded around the vertices.
+ * @param innerRounding Optional rounding parameters for the vertices on the [innerRadius]. If
+ * null (the default value), inner vertices will use the [rounding] or [perVertexRounding]
+ * parameters instead.
+ * @param perVertexRounding The [CornerRounding] properties of every vertex. If this
+ * parameter is not null, then it must have the same size as 2 * [numVerticesPerRadius]. If this
+ * parameter is null, then the polygon will use the [rounding] parameter for every vertex instead.
+ * The default value is null.
+ * @param center The center of the polygon, around which all vertices will be placed. The
+ * default center is at (0,0).
+ *
+ * @throws IllegalArgumentException if either [radius] or [innerRadius] are <= 0 or
+ * [innerRadius] > [radius].
  */
 @JvmOverloads
 fun Star(
-    numOuterVertices: Int,
-    @FloatRange(from = 0.0, to = 1.0, fromInclusive = false, toInclusive = false)
-    innerRadiusRatio: Float,
+    numVerticesPerRadius: Int,
     radius: Float = 1f,
+    innerRadius: Float = .5f,
     rounding: CornerRounding = CornerRounding.Unrounded,
     innerRounding: CornerRounding? = null,
     perVertexRounding: List<CornerRounding>? = null,
     center: PointF = Zero
 ): RoundedPolygon {
-    if (innerRadiusRatio <= 0f || innerRadiusRatio >= 1f) {
-        throw IllegalArgumentException("Inner radius ratio must be in range (0,1), exclusive" +
-            "of 0 and 1")
+    if (radius <= 0f || innerRadius <= 0f) {
+        throw IllegalArgumentException("Star radii must both be greater than 0")
+    }
+    if (innerRadius >= radius) {
+        throw IllegalArgumentException("innerRadius must be less than radius")
     }
 
     var pvRounding = perVertexRounding
     // If no per-vertex rounding supplied and caller asked for inner rounding,
     // create per-vertex rounding list based on supplied outer/inner rounding parameters
     if (pvRounding == null && innerRounding != null) {
-        pvRounding = (0 until numOuterVertices).flatMap {
+        pvRounding = (0 until numVerticesPerRadius).flatMap {
             listOf(rounding, innerRounding)
         }
     }
     // Star polygon is just a polygon with all vertices supplied (where we generate
     // those vertices to be on the inner/outer radii)
-    return RoundedPolygon((0 until numOuterVertices).flatMap {
+    return RoundedPolygon((0 until numVerticesPerRadius).flatMap {
         listOf(
-            radialToCartesian(radius, (FloatPi / numOuterVertices * 2 * it), center),
-            radialToCartesian(radius * innerRadiusRatio,
-                FloatPi / numOuterVertices * (2 * it + 1), center)
+            radialToCartesian(radius, (FloatPi / numVerticesPerRadius * 2 * it), center),
+            radialToCartesian(innerRadius, FloatPi / numVerticesPerRadius * (2 * it + 1), center)
         )
     }, rounding, pvRounding, center)
 }
diff --git a/graphics/integration-tests/testapp-compose/build.gradle b/graphics/integration-tests/testapp-compose/build.gradle
index 97fce58..840935f 100644
--- a/graphics/integration-tests/testapp-compose/build.gradle
+++ b/graphics/integration-tests/testapp-compose/build.gradle
@@ -36,6 +36,7 @@
     implementation("androidx.compose.runtime:runtime:1.3.3")
     implementation("androidx.compose.ui:ui:1.3.3")
     implementation("androidx.core:core-ktx:1.9.0")
+    implementation("androidx.fragment:fragment:1.5.6")
 }
 
 android {
diff --git a/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/MainActivity.kt b/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/MainActivity.kt
index 26166e8..91a8db6 100644
--- a/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/MainActivity.kt
+++ b/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/MainActivity.kt
@@ -182,28 +182,28 @@
             //
             ShapeParameters(
                 sides = 12,
-                innerRadiusRatio = .928f,
+                innerRadius = .928f,
                 roundness = .1f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
             // Clover
             ShapeParameters(
                 sides = 4,
-                innerRadiusRatio = .352f,
+                innerRadius = .352f,
                 roundness = .32f,
                 rotation = 45f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
             // Alice
             ShapeParameters(
-                innerRadiusRatio = 0.1f,
+                innerRadius = 0.1f,
                 roundness = 0.22f,
                 shapeId = ShapeParameters.ShapeId.Triangle
             ),
             // Wiggle Star
             ShapeParameters(
                 sides = 8,
-                innerRadiusRatio = .784f,
+                innerRadius = .784f,
                 roundness = .16f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
@@ -212,20 +212,20 @@
             // Wovel
             ShapeParameters(
                 sides = 15,
-                innerRadiusRatio = .892f,
+                innerRadius = .892f,
                 roundness = 1f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
             // BlobR
             ShapeParameters(
-                innerRadiusRatio = .19f,
+                innerRadius = .19f,
                 roundness = 0.86f,
                 rotation = -45f,
                 shapeId = ShapeParameters.ShapeId.Blob
             ),
             // BlobL
             ShapeParameters(
-                innerRadiusRatio = .19f,
+                innerRadius = .19f,
                 roundness = 0.86f,
                 rotation = 45f,
                 shapeId = ShapeParameters.ShapeId.Blob
@@ -233,7 +233,7 @@
             // Scalop
             ShapeParameters(
                 sides = 12,
-                innerRadiusRatio = .928f,
+                innerRadius = .928f,
                 roundness = .928f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
@@ -268,14 +268,14 @@
             ShapeParameters(
                 sides = 5,
                 rotation = -360f / 20,
-                innerRadiusRatio = .3f,
+                innerRadius = .3f,
                 shapeId = ShapeParameters.ShapeId.Star
             ),
 
             // 8-Sided Star
             ShapeParameters(
                 sides = 8,
-                innerRadiusRatio = .6f,
+                innerRadius = .6f,
                 shapeId = ShapeParameters.ShapeId.Star
             )
         )
diff --git a/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/ShapeEditor.kt b/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/ShapeEditor.kt
index aec2f4b..c7f98bb 100644
--- a/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/ShapeEditor.kt
+++ b/graphics/integration-tests/testapp-compose/src/main/java/androidx/graphics/shapes/testcompose/ShapeEditor.kt
@@ -75,7 +75,7 @@
 
 class ShapeParameters(
     sides: Int = 5,
-    innerRadiusRatio: Float = 0.5f,
+    innerRadius: Float = 0.5f,
     roundness: Float = 0f,
     smooth: Float = 0f,
     innerRoundness: Float = roundness,
@@ -84,7 +84,7 @@
     shapeId: ShapeId = ShapeId.Polygon
 ) {
     internal val sides = mutableStateOf(sides.toFloat())
-    internal val innerRadiusRatio = mutableStateOf(innerRadiusRatio)
+    internal val innerRadius = mutableStateOf(innerRadius)
     internal val roundness = mutableStateOf(roundness)
     internal val smooth = mutableStateOf(smooth)
     internal val innerRoundness = mutableStateOf(innerRoundness)
@@ -95,7 +95,7 @@
 
     fun copy() = ShapeParameters(
         this.sides.value.roundToInt(),
-        this.innerRadiusRatio.value,
+        this.innerRadius.value,
         this.roundness.value,
         this.smooth.value,
         this.innerRoundness.value,
@@ -124,8 +124,8 @@
     internal val shapes = listOf(
         ShapeItem("Star", shapegen = {
                 Star(
-                    numOuterVertices = this.sides.value.roundToInt(),
-                    innerRadiusRatio = this.innerRadiusRatio.value,
+                    numVerticesPerRadius = this.sides.value.roundToInt(),
+                    innerRadius = this.innerRadius.value,
                     rounding = CornerRounding(this.roundness.value, this.smooth.value),
                     innerRounding = CornerRounding(
                         this.innerRoundness.value,
@@ -136,7 +136,7 @@
             debugDump = {
                 debugLog(
                     "ShapeParameters(sides = ${this.sides.value.roundToInt()}, " +
-                        "innerRadiusRatio = ${this.innerRadiusRatio.value}f, " +
+                        "innerRadius = ${this.innerRadius.value}f, " +
                         "roundness = ${this.roundness.value}f, " +
                         "smooth = ${this.smooth.value}f, " +
                         "innerRoundness = ${this.innerRoundness.value}f, " +
@@ -167,7 +167,7 @@
                 val points = listOf(
                     radialToCartesian(1f, 270f.toRadians()),
                     radialToCartesian(1f, 30f.toRadians()),
-                    radialToCartesian(this.innerRadiusRatio.value, 90f.toRadians()),
+                    radialToCartesian(this.innerRadius.value, 90f.toRadians()),
                     radialToCartesian(1f, 150f.toRadians()),
                 )
                 RoundedPolygon(
@@ -178,7 +178,7 @@
             },
             debugDump = {
                 debugLog(
-                    "ShapeParameters(innerRadiusRatio = ${this.innerRadiusRatio.value}f, " +
+                    "ShapeParameters(innerRadius = ${this.innerRadius.value}f, " +
                         "smooth = ${this.smooth.value}f, " +
                         rotationAsString() +
                         "shapeId = ShapeParameters.ShapeId.Triangle)"
@@ -188,7 +188,7 @@
         ),
         ShapeItem(
             "Blob", shapegen = {
-                val sx = this.innerRadiusRatio.value.coerceAtLeast(0.1f)
+                val sx = this.innerRadius.value.coerceAtLeast(0.1f)
                 val sy = this.roundness.value.coerceAtLeast(0.1f)
                 RoundedPolygon(
                     listOf(
@@ -283,11 +283,11 @@
         }
         MySlider("Sides", 3f, 20f, 1f, params.sides, shapeParams.usesSides)
         MySlider(
-            "InnerRadiusRatio",
+            "InnerRadius",
             0.1f,
             0.999f,
             0f,
-            params.innerRadiusRatio,
+            params.innerRadius,
             shapeParams.usesInnerRatio
         )
         MySlider("RoundRadius", 0f, 1f, 0f, params.roundness, shapeParams.usesRoundness)
diff --git a/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/MaterialShapes.kt b/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/MaterialShapes.kt
index 0a78604..e3b0444 100644
--- a/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/MaterialShapes.kt
+++ b/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/MaterialShapes.kt
@@ -104,18 +104,18 @@
 
         @JvmStatic
         fun scallop(): RoundedPolygon {
-            return Star(12, .928f, rounding = CornerRounding(radius = .928f))
+            return Star(12, innerRadius = .928f, rounding = CornerRounding(radius = .928f))
         }
 
         @JvmOverloads
         @JvmStatic
         fun clover(
             rounding: Float = .32f,
-            innerRadiusRatio: Float = .352f,
+            innerRadius: Float = .352f,
             innerRounding: CornerRounding? = null,
             scale: Float = 1f
         ): RoundedPolygon {
-            val poly = Star(4, innerRadiusRatio,
+            val poly = Star(4, innerRadius = innerRadius,
                 rounding = CornerRounding(rounding * scale),
                 innerRounding = innerRounding)
             return poly
diff --git a/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/ShapeActivity.kt b/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/ShapeActivity.kt
index d24d838..5571e62 100644
--- a/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/ShapeActivity.kt
+++ b/graphics/integration-tests/testapp/src/main/java/androidx/graphics/shapes/test/ShapeActivity.kt
@@ -115,11 +115,11 @@
         val rounding = CornerRounding(.1f, .5f)
         val starRounding = CornerRounding(.05f, .25f)
         shapes.add(RoundedPolygon(numVertices = 4, rounding = rounding))
-        shapes.add(Star(8, .4f, rounding = starRounding))
-        shapes.add(Star(8, innerRadiusRatio = .4f, rounding = starRounding,
+        shapes.add(Star(8, radius = 1f, innerRadius = .4f, rounding = starRounding))
+        shapes.add(Star(8, radius = 1f, innerRadius = .4f, rounding = starRounding,
             innerRounding = CornerRounding.Unrounded))
         shapes.add(
-            MaterialShapes.clover(rounding = .352f, innerRadiusRatio = .1f,
+            MaterialShapes.clover(rounding = .352f, innerRadius = .1f,
             innerRounding = Unrounded))
         shapes.add(RoundedPolygon(3))
     }
diff --git a/health/connect/connect-client/api/current.txt b/health/connect/connect-client/api/current.txt
index 1557dcd..c933c01 100644
--- a/health/connect/connect-client/api/current.txt
+++ b/health/connect/connect-client/api/current.txt
@@ -13,14 +13,14 @@
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public androidx.health.connect.client.PermissionController getPermissionController();
+    method public default static int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public default static int getSdkStatus(android.content.Context context);
     method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method @Deprecated public default static boolean isApiSupported();
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecord(kotlin.reflect.KClass<T> recordType, String recordId, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordResponse<T>>);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecords(androidx.health.connect.client.request.ReadRecordsRequest<T> request, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordsResponse<T>>);
-    method public default static int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public default static int sdkStatus(android.content.Context context);
     method public suspend Object? updateRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     property public default static String ACTION_HEALTH_CONNECT_SETTINGS;
     property public abstract androidx.health.connect.client.PermissionController permissionController;
@@ -34,11 +34,11 @@
     method public String getHealthConnectSettingsAction();
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public int getSdkStatus(android.content.Context context);
     method @Deprecated public boolean isApiSupported();
     method @Deprecated public boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public boolean isProviderAvailable(android.content.Context context);
-    method public int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public int sdkStatus(android.content.Context context);
     property public final String ACTION_HEALTH_CONNECT_SETTINGS;
     field public static final int SDK_AVAILABLE = 3; // 0x3
     field public static final int SDK_UNAVAILABLE = 1; // 0x1
diff --git a/health/connect/connect-client/api/public_plus_experimental_current.txt b/health/connect/connect-client/api/public_plus_experimental_current.txt
index 1557dcd..c933c01 100644
--- a/health/connect/connect-client/api/public_plus_experimental_current.txt
+++ b/health/connect/connect-client/api/public_plus_experimental_current.txt
@@ -13,14 +13,14 @@
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public androidx.health.connect.client.PermissionController getPermissionController();
+    method public default static int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public default static int getSdkStatus(android.content.Context context);
     method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method @Deprecated public default static boolean isApiSupported();
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecord(kotlin.reflect.KClass<T> recordType, String recordId, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordResponse<T>>);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecords(androidx.health.connect.client.request.ReadRecordsRequest<T> request, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordsResponse<T>>);
-    method public default static int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public default static int sdkStatus(android.content.Context context);
     method public suspend Object? updateRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     property public default static String ACTION_HEALTH_CONNECT_SETTINGS;
     property public abstract androidx.health.connect.client.PermissionController permissionController;
@@ -34,11 +34,11 @@
     method public String getHealthConnectSettingsAction();
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public int getSdkStatus(android.content.Context context);
     method @Deprecated public boolean isApiSupported();
     method @Deprecated public boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public boolean isProviderAvailable(android.content.Context context);
-    method public int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public int sdkStatus(android.content.Context context);
     property public final String ACTION_HEALTH_CONNECT_SETTINGS;
     field public static final int SDK_AVAILABLE = 3; // 0x3
     field public static final int SDK_UNAVAILABLE = 1; // 0x1
diff --git a/health/connect/connect-client/api/restricted_current.txt b/health/connect/connect-client/api/restricted_current.txt
index 8b5c16b..0b5157d 100644
--- a/health/connect/connect-client/api/restricted_current.txt
+++ b/health/connect/connect-client/api/restricted_current.txt
@@ -13,14 +13,14 @@
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public default static androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
     method public androidx.health.connect.client.PermissionController getPermissionController();
+    method public default static int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public default static int getSdkStatus(android.content.Context context);
     method public suspend Object? insertRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.InsertRecordsResponse>);
     method @Deprecated public default static boolean isApiSupported();
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public default static boolean isProviderAvailable(android.content.Context context);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecord(kotlin.reflect.KClass<T> recordType, String recordId, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordResponse<T>>);
     method public suspend <T extends androidx.health.connect.client.records.Record> Object? readRecords(androidx.health.connect.client.request.ReadRecordsRequest<T> request, kotlin.coroutines.Continuation<? super androidx.health.connect.client.response.ReadRecordsResponse<T>>);
-    method public default static int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public default static int sdkStatus(android.content.Context context);
     method public suspend Object? updateRecords(java.util.List<? extends androidx.health.connect.client.records.Record> records, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     property public default static String ACTION_HEALTH_CONNECT_SETTINGS;
     property public abstract androidx.health.connect.client.PermissionController permissionController;
@@ -34,11 +34,11 @@
     method public String getHealthConnectSettingsAction();
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context, optional String providerPackageName);
     method public androidx.health.connect.client.HealthConnectClient getOrCreate(android.content.Context context);
+    method public int getSdkStatus(android.content.Context context, optional String providerPackageName);
+    method public int getSdkStatus(android.content.Context context);
     method @Deprecated public boolean isApiSupported();
     method @Deprecated public boolean isProviderAvailable(android.content.Context context, optional String providerPackageName);
     method @Deprecated public boolean isProviderAvailable(android.content.Context context);
-    method public int sdkStatus(android.content.Context context, optional String providerPackageName);
-    method public int sdkStatus(android.content.Context context);
     property public final String ACTION_HEALTH_CONNECT_SETTINGS;
     field public static final int SDK_AVAILABLE = 3; // 0x3
     field public static final int SDK_UNAVAILABLE = 1; // 0x1
diff --git a/health/connect/connect-client/samples/src/main/java/androidx/health/connect/client/samples/AvailabilitySamples.kt b/health/connect/connect-client/samples/src/main/java/androidx/health/connect/client/samples/AvailabilitySamples.kt
index f14f83c..6f67507 100644
--- a/health/connect/connect-client/samples/src/main/java/androidx/health/connect/client/samples/AvailabilitySamples.kt
+++ b/health/connect/connect-client/samples/src/main/java/androidx/health/connect/client/samples/AvailabilitySamples.kt
@@ -26,7 +26,7 @@
 
 @Sampled
 suspend fun AvailabilityCheckSamples(context: Context, providerPackageName: String) {
-    val availabilityStatus = HealthConnectClient.sdkStatus(context, providerPackageName)
+    val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)
     if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
         return // early return as there is no viable integration
     }
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
index a7f4d85..96f9b86 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/HealthConnectClient.kt
@@ -368,7 +368,7 @@
         @JvmOverloads
         @JvmStatic
         @AvailabilityStatus
-        fun sdkStatus(
+        fun getSdkStatus(
             context: Context,
             providerPackageName: String = DEFAULT_PROVIDER_PACKAGE_NAME,
         ): Int {
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/exerciseroute/ExerciseRoute.kt b/health/connect/connect-client/src/main/java/androidx/health/platform/client/exerciseroute/ExerciseRoute.kt
new file mode 100644
index 0000000..0770dd95
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/exerciseroute/ExerciseRoute.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.platform.client.exerciseroute
+
+import android.os.Parcelable
+import androidx.health.platform.client.impl.data.ProtoParcelable
+import androidx.health.platform.client.proto.DataProto
+
+/**
+ * Internal parcelable wrapper over proto object.
+ *
+ * @suppress
+ */
+class ExerciseRoute(override val proto: DataProto.DataPoint.SubTypeDataList) :
+    ProtoParcelable<DataProto.DataPoint.SubTypeDataList>() {
+
+    companion object {
+        @JvmField
+        val CREATOR: Parcelable.Creator<ExerciseRoute> = newCreator {
+            val proto = DataProto.DataPoint.SubTypeDataList.parseFrom(it)
+            ExerciseRoute(proto)
+        }
+    }
+}
diff --git a/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt b/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
index ca53b37..d839bb1 100644
--- a/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
+++ b/health/connect/connect-client/src/test/java/androidx/health/connect/client/HealthConnectClientTest.kt
@@ -54,7 +54,7 @@
         assertThat(HealthConnectClient.isApiSupported()).isTrue()
         assertThat(HealthConnectClient.isProviderAvailable(context, PROVIDER_PACKAGE_NAME))
             .isFalse()
-        assertThat(HealthConnectClient.sdkStatus(context, PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.getSdkStatus(context, PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED)
         assertThrows(IllegalStateException::class.java) {
             HealthConnectClient.getOrCreate(context, PROVIDER_PACKAGE_NAME)
@@ -68,7 +68,7 @@
         installPackage(context, PROVIDER_PACKAGE_NAME, versionCode = 35001, enabled = false)
         assertThat(HealthConnectClient.isProviderAvailable(context, PROVIDER_PACKAGE_NAME))
             .isFalse()
-        assertThat(HealthConnectClient.sdkStatus(context, PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.getSdkStatus(context, PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED)
         assertThrows(IllegalStateException::class.java) {
             HealthConnectClient.getOrCreate(context, PROVIDER_PACKAGE_NAME)
@@ -82,7 +82,7 @@
         installPackage(context, PROVIDER_PACKAGE_NAME, versionCode = 35001, enabled = true)
         assertThat(HealthConnectClient.isProviderAvailable(context, PROVIDER_PACKAGE_NAME))
             .isFalse()
-        assertThat(HealthConnectClient.sdkStatus(context, PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.getSdkStatus(context, PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED)
         assertThrows(IllegalStateException::class.java) {
             HealthConnectClient.getOrCreate(context, PROVIDER_PACKAGE_NAME)
@@ -101,7 +101,7 @@
         installService(context, HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME)
 
         assertThat(HealthConnectClient.isProviderAvailable(context)).isFalse()
-        assertThat(HealthConnectClient.sdkStatus(context, PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.getSdkStatus(context, PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED)
         assertThrows(IllegalStateException::class.java) {
             HealthConnectClient.getOrCreate(context)
@@ -120,7 +120,7 @@
         installService(context, HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME)
 
         assertThat(HealthConnectClient.isProviderAvailable(context)).isTrue()
-        assertThat(HealthConnectClient.sdkStatus(
+        assertThat(HealthConnectClient.getSdkStatus(
             context, HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_AVAILABLE)
         HealthConnectClient.getOrCreate(context)
@@ -133,7 +133,7 @@
         assertThat(HealthConnectClient.isApiSupported()).isFalse()
         assertThat(HealthConnectClient.isProviderAvailable(context, PROVIDER_PACKAGE_NAME))
             .isFalse()
-        assertThat(HealthConnectClient.sdkStatus(context, PROVIDER_PACKAGE_NAME))
+        assertThat(HealthConnectClient.getSdkStatus(context, PROVIDER_PACKAGE_NAME))
             .isEqualTo(HealthConnectClient.SDK_UNAVAILABLE)
         assertThrows(UnsupportedOperationException::class.java) {
             HealthConnectClient.getOrCreate(context, PROVIDER_PACKAGE_NAME)
diff --git a/health/health-services-client/api/1.0.0-beta04.txt b/health/health-services-client/api/1.0.0-beta04.txt
new file mode 100644
index 0000000..f2df4c7
--- /dev/null
+++ b/health/health-services-client/api/1.0.0-beta04.txt
@@ -0,0 +1,910 @@
+// Signature format: 4.0
+package androidx.health.services.client {
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateCallbackAsync(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseCapabilities> getCapabilitiesAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfoAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLapAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExerciseAsync(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> prepareExerciseAsync(androidx.health.services.client.data.WarmUpConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> removeGoalFromActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExerciseAsync();
+    method public void setUpdateCallback(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public void setUpdateCallback(java.util.concurrent.Executor executor, androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExerciseAsync(androidx.health.services.client.data.ExerciseConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> updateExerciseTypeConfigAsync(androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig);
+  }
+
+  public final class ExerciseClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? addGoalToActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearUpdateCallback(androidx.health.services.client.ExerciseClient, androidx.health.services.client.ExerciseUpdateCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? endExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCurrentExerciseInfo(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseInfo>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? markLap(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideAutoPauseAndResumeForActiveExercise(androidx.health.services.client.ExerciseClient, boolean enabled, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideBatchingModesForActiveExercise(androidx.health.services.client.ExerciseClient, java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? pauseExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? prepareExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.WarmUpConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? removeGoalFromActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? resumeExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? startExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? updateExerciseTypeConfig(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  public interface ExerciseUpdateCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onExerciseUpdateReceived(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummaryReceived(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+    method public void onRegistered();
+    method public void onRegistrationFailed(Throwable throwable);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public final class HealthServicesException extends java.lang.Exception {
+    ctor public HealthServicesException(String message);
+  }
+
+  public final class ListenableFutureExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend <T> Object? awaitWithException(com.google.common.util.concurrent.ListenableFuture<T>, kotlin.coroutines.Continuation<? super T>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onDataReceived(androidx.health.services.client.data.DataPointContainer data);
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilitiesAsync();
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, java.util.concurrent.Executor executor, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterMeasureCallbackAsync(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+  }
+
+  public final class MeasureClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.MeasureClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.MeasureCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? unregisterMeasureCallback(androidx.health.services.client.MeasureClient, androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface PassiveListenerCallback {
+    method public default void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public default void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public default void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public default void onPermissionLost();
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+    method public default void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public abstract class PassiveListenerService extends android.app.Service {
+    ctor public PassiveListenerService();
+    method public final android.os.IBinder? onBind(android.content.Intent intent);
+    method public void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public void onPermissionLost();
+    method public void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerCallbackAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerServiceAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilitiesAsync();
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, androidx.health.services.client.PassiveListenerCallback callback);
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, java.util.concurrent.Executor executor, androidx.health.services.client.PassiveListenerCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setPassiveListenerServiceAsync(Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config);
+  }
+
+  public final class PassiveMonitoringClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerCallback(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.PassiveMonitoringCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? setPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AggregateDataType<T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public AggregateDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface Availability {
+    method public int getId();
+    property public abstract int id;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+  }
+
+  public final class BatchingMode {
+    field public static final androidx.health.services.client.data.BatchingMode.Companion Companion;
+    field public static final androidx.health.services.client.data.BatchingMode HEART_RATE_5_SECONDS;
+  }
+
+  public static final class BatchingMode.Companion {
+  }
+
+  public final class ComparisonType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType UNKNOWN;
+  }
+
+  public static final class ComparisonType.Companion {
+  }
+
+  public final class CumulativeDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public CumulativeDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.CumulativeDataPoint<T>> dataType, T total, java.time.Instant start, java.time.Instant end);
+    method public java.time.Instant getEnd();
+    method public java.time.Instant getStart();
+    method public T getTotal();
+    property public final java.time.Instant end;
+    property public final java.time.Instant start;
+    property public final T total;
+  }
+
+  public abstract class DataPoint<T> {
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> getDataType();
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> dataType;
+  }
+
+  public abstract class DataPointAccuracy {
+    ctor public DataPointAccuracy();
+  }
+
+  public final class DataPointContainer {
+    ctor public DataPointContainer(java.util.Map<androidx.health.services.client.data.DataType<?,?>,? extends java.util.List<? extends androidx.health.services.client.data.DataPoint<?>>> dataPoints);
+    ctor public DataPointContainer(java.util.List<? extends androidx.health.services.client.data.DataPoint<?>> dataPointList);
+    method public java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> getCumulativeDataPoints();
+    method public <T, D extends androidx.health.services.client.data.DataPoint<T>> java.util.List<D> getData(androidx.health.services.client.data.DeltaDataType<T,D> type);
+    method public <T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> D? getData(androidx.health.services.client.data.AggregateDataType<T,D> type);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> getIntervalDataPoints();
+    method public java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> getSampleDataPoints();
+    method public java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> getStatisticalDataPoints();
+    property public final java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> cumulativeDataPoints;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> intervalDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> sampleDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> statisticalDataPoints;
+  }
+
+  public abstract class DataType<T, D extends androidx.health.services.client.data.DataPoint<T>> {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass, boolean isAggregate);
+    method public final String getName();
+    method public final Class<T> getValueClass();
+    property public final String name;
+    property public final Class<T> valueClass;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> ACTIVE_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> CALORIES_TOTAL;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DECLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> DECLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> DECLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_GAIN;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_GAIN_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_LOSS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_LOSS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> FLAT_GROUND_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> FLAT_GROUND_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLOORS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> GOLF_SHOT_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> GOLF_SHOT_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> HEART_RATE_BPM_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> INCLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> INCLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> INCLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<androidx.health.services.client.data.LocationData,androidx.health.services.client.data.SampleDataPoint<androidx.health.services.client.data.LocationData>> LOCATION;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> PACE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> PACE_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> REP_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> REP_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RUNNING_STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> SPEED;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> SPEED_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS_DAILY;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.SampleDataPoint<java.lang.Long>> STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Long>> STEPS_PER_MINUTE_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> SWIMMING_STROKES_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> VO2_MAX;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> VO2_MAX_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> WALKING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> WALKING_STEPS_TOTAL;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public static final class DataType.TimeType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataType.TimeType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    field public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+    field public static final androidx.health.services.client.data.DataType.TimeType UNKNOWN;
+  }
+
+  public static final class DataType.TimeType.Companion {
+  }
+
+  public final class DataTypeAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataTypeAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.DataTypeAvailability AVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE_DEVICE_OFF_BODY;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNKNOWN;
+  }
+
+  public static final class DataTypeAvailability.Companion {
+    method public androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+  }
+
+  public final class DataTypeCondition<T extends java.lang.Number, D extends androidx.health.services.client.data.DataType<T, ? extends androidx.health.services.client.data.DataPoint<T>>> {
+    ctor public DataTypeCondition(D dataType, T threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public D getDataType();
+    method public T getThreshold();
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final D dataType;
+    property public final T threshold;
+  }
+
+  public final class DeltaDataType<T, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public DeltaDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  public final class ExerciseCapabilities {
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities, optional java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides);
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseTypeCapabilities getExerciseTypeCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getSupportedBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> getTypeToCapabilities();
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities;
+  }
+
+  public final class ExerciseConfig {
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig, optional java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public androidx.health.services.client.data.ExerciseTypeConfig? getExerciseTypeConfig();
+    method public float getSwimmingPoolLengthMeters();
+    method public boolean isAutoPauseAndResumeEnabled();
+    method public boolean isGpsEnabled();
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    property public final androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig;
+    property public final boolean isAutoPauseAndResumeEnabled;
+    property public final boolean isGpsEnabled;
+    property public final float swimmingPoolLengthMeters;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+    field public static final float SWIMMING_POOL_LENGTH_UNSPECIFIED = 0.0f;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setBatchingModeOverrides(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseTypeConfig(androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsAutoPauseAndResumeEnabled(boolean isAutoPauseAndResumeEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsGpsEnabled(boolean isGpsEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setSwimmingPoolLengthMeters(float swimmingPoolLength);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public final class ExerciseGoal<T extends java.lang.Number> implements android.os.Parcelable {
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public T? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final T? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal<?>> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+  }
+
+  public final class ExerciseGoalType {
+    method public static androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    field public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo {
+    ctor public ExerciseInfo(int exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final int exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+  public final class ExerciseLapSummary {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.DataPointContainer lapMetrics);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public androidx.health.services.client.data.DataPointContainer getLapMetrics();
+    method public java.time.Instant getStartTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final androidx.health.services.client.data.DataPointContainer lapMetrics;
+    property public final java.time.Instant startTime;
+  }
+
+  public final class ExerciseState {
+    method public static androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public int getId();
+    method public String getName();
+    method public boolean isEnded();
+    method public boolean isEnding();
+    method public boolean isPaused();
+    method public boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isEnding;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseState ENDED;
+    field public static final androidx.health.services.client.data.ExerciseState ENDING;
+    field public static final androidx.health.services.client.data.ExerciseState PREPARING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public final class ExerciseStateInfo {
+    ctor public ExerciseStateInfo(androidx.health.services.client.data.ExerciseState exerciseState, int exerciseEndReason);
+    method public int getEndReason();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    property public final int endReason;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final androidx.health.services.client.data.ExerciseStateInfo.Companion Companion;
+  }
+
+  public static final class ExerciseStateInfo.Companion {
+  }
+
+  public final class ExerciseType {
+    method public static androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseType ALPINE_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType BACKPACKING;
+    field public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    field public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    field public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    field public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    field public static final androidx.health.services.client.data.ExerciseType BOXING;
+    field public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    field public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    field public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    field public static final androidx.health.services.client.data.ExerciseType CROSS_COUNTRY_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseType DANCING;
+    field public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    field public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    field public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    field public static final androidx.health.services.client.data.ExerciseType FENCING;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    field public static final androidx.health.services.client.data.ExerciseType FORWARD_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    field public static final androidx.health.services.client.data.ExerciseType GOLF;
+    field public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    field public static final androidx.health.services.client.data.ExerciseType GYMNASTICS;
+    field public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    field public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType HIKING;
+    field public static final androidx.health.services.client.data.ExerciseType HORSE_RIDING;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType INLINE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    field public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    field public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    field public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    field public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    field public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    field public static final androidx.health.services.client.data.ExerciseType MOUNTAIN_BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType ORIENTEERING;
+    field public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    field public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    field public static final androidx.health.services.client.data.ExerciseType PILATES;
+    field public static final androidx.health.services.client.data.ExerciseType PLANK;
+    field public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    field public static final androidx.health.services.client.data.ExerciseType SAILING;
+    field public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    field public static final androidx.health.services.client.data.ExerciseType SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    field public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    field public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    field public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    field public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    field public static final androidx.health.services.client.data.ExerciseType SURFING;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    field public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    field public static final androidx.health.services.client.data.ExerciseType UPPER_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    field public static final androidx.health.services.client.data.ExerciseType WALKING;
+    field public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    field public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    field public static final androidx.health.services.client.data.ExerciseType WORKOUT;
+    field public static final androidx.health.services.client.data.ExerciseType YACHTING;
+    field public static final androidx.health.services.client.data.ExerciseType YOGA;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseTypeCapabilities {
+    ctor public ExerciseTypeCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypes, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+  }
+
+  public abstract class ExerciseTypeConfig {
+    field public static final androidx.health.services.client.data.ExerciseTypeConfig.Companion Companion;
+  }
+
+  public static final class ExerciseTypeConfig.Companion {
+  }
+
+  public final class ExerciseUpdate {
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.IntervalDataPoint<?> dataPoint);
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.SampleDataPoint<?> dataPoint);
+    method public androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? getActiveDurationCheckpoint();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseStateInfo getExerciseStateInfo();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> getLatestAchievedGoals();
+    method public androidx.health.services.client.data.DataPointContainer getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant? getStartTime();
+    method public java.time.Duration getUpdateDurationFromBoot();
+    property public final androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? activeDurationCheckpoint;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseStateInfo exerciseStateInfo;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> latestAchievedGoals;
+    property public final androidx.health.services.client.data.DataPointContainer latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant? startTime;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.ActiveDurationCheckpoint {
+    ctor public ExerciseUpdate.ActiveDurationCheckpoint(java.time.Instant time, java.time.Duration activeDuration);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant time;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public final class GolfExerciseTypeConfig extends androidx.health.services.client.data.ExerciseTypeConfig {
+    ctor public GolfExerciseTypeConfig(optional androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo);
+    method public androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo getGolfShotTrackingPlaceInfo();
+    property public final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo {
+    method public int getPlaceInfoId();
+    property public final int placeInfoId;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion Companion;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_FAIRWAY;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_PUTTING_GREEN;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_TEE_BOX;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_UNSPECIFIED;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion {
+  }
+
+  public final class HealthEvent {
+    ctor public HealthEvent(androidx.health.services.client.data.HealthEvent.Type type, java.time.Instant eventTime, androidx.health.services.client.data.DataPointContainer metrics);
+    method public java.time.Instant getEventTime();
+    method public androidx.health.services.client.data.DataPointContainer getMetrics();
+    method public androidx.health.services.client.data.HealthEvent.Type getType();
+    property public final java.time.Instant eventTime;
+    property public final androidx.health.services.client.data.DataPointContainer metrics;
+    property public final androidx.health.services.client.data.HealthEvent.Type type;
+  }
+
+  public static final class HealthEvent.Type {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HealthEvent.Type.Companion Companion;
+    field public static final androidx.health.services.client.data.HealthEvent.Type FALL_DETECTED;
+    field public static final androidx.health.services.client.data.HealthEvent.Type UNKNOWN;
+  }
+
+  public static final class HealthEvent.Type.Companion {
+  }
+
+  public final class HeartRateAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public HeartRateAccuracy(androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus);
+    method public androidx.health.services.client.data.HeartRateAccuracy.SensorStatus getSensorStatus();
+    property public final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_HIGH;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_LOW;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_MEDIUM;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus.Companion Companion;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus NO_CONTACT;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNKNOWN;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNRELIABLE;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus.Companion {
+  }
+
+  public final class IntervalDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public IntervalDataPoint(androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType, T value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class LocationAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public LocationAccuracy(@FloatRange(from=0.0) double horizontalPositionErrorMeters, optional @FloatRange(from=0.0) double verticalPositionErrorMeters);
+    method public double getHorizontalPositionErrorMeters();
+    method public double getVerticalPositionErrorMeters();
+    property public final double horizontalPositionErrorMeters;
+    property public final double verticalPositionErrorMeters;
+    field public static final androidx.health.services.client.data.LocationAccuracy.Companion Companion;
+  }
+
+  public static final class LocationAccuracy.Companion {
+  }
+
+  public final class LocationAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.LocationAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_TETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_UNTETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.LocationAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.LocationAvailability NO_GNSS;
+    field public static final androidx.health.services.client.data.LocationAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.LocationAvailability UNKNOWN;
+  }
+
+  public static final class LocationAvailability.Companion {
+    method public androidx.health.services.client.data.LocationAvailability? fromId(int id);
+  }
+
+  public final class LocationData {
+    ctor public LocationData(@FloatRange(from=-90.0, to=90.0) double latitude, @FloatRange(from=-180.0, to=180.0) double longitude, optional double altitude, optional double bearing);
+    method public double getAltitude();
+    method public double getBearing();
+    method public double getLatitude();
+    method public double getLongitude();
+    property public final double altitude;
+    property public final double bearing;
+    property public final double latitude;
+    property public final double longitude;
+    field public static final double ALTITUDE_UNAVAILABLE = (0.0/0.0);
+    field public static final double BEARING_UNAVAILABLE = (0.0/0.0);
+  }
+
+  public final class MeasureCapabilities {
+    ctor public MeasureCapabilities(java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getSupportedDataTypesMeasure();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure;
+  }
+
+  public final class MilestoneMarkerSummary {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal, androidx.health.services.client.data.DataPointContainer summaryMetrics);
+    method public androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.DataPointContainer getSummaryMetrics();
+    property public final androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.DataPointContainer summaryMetrics;
+  }
+
+  public final class PassiveGoal {
+    ctor public PassiveGoal(androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition);
+    method public androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> getDataTypeCondition();
+    property public final androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition;
+  }
+
+  public final class PassiveListenerConfig {
+    ctor public PassiveListenerConfig(java.util.Set<? extends androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes, boolean shouldUserActivityInfoBeRequested, java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public static androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+    method public java.util.Set<androidx.health.services.client.data.PassiveGoal> getDailyGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> getDataTypes();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getHealthEventTypes();
+    method public boolean getShouldUserActivityInfoBeRequested();
+    property public final java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes;
+    property public final boolean shouldUserActivityInfoBeRequested;
+    field public static final androidx.health.services.client.data.PassiveListenerConfig.Companion Companion;
+  }
+
+  public static final class PassiveListenerConfig.Builder {
+    ctor public PassiveListenerConfig.Builder();
+    method public androidx.health.services.client.data.PassiveListenerConfig build();
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDailyGoals(java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setHealthEventTypes(java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setShouldUserActivityInfoBeRequested(boolean shouldUserActivityInfoBeRequested);
+  }
+
+  public static final class PassiveListenerConfig.Companion {
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+  }
+
+  public final class PassiveMonitoringCapabilities {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes, java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveMonitoring();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getSupportedHealthEventTypes();
+    method public java.util.Set<androidx.health.services.client.data.UserActivityState> getSupportedUserActivityStates();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes;
+    property public final java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates;
+  }
+
+  public final class PassiveMonitoringUpdate {
+    ctor public PassiveMonitoringUpdate(androidx.health.services.client.data.DataPointContainer dataPoints, java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates);
+    method public androidx.health.services.client.data.DataPointContainer getDataPoints();
+    method public java.util.List<androidx.health.services.client.data.UserActivityInfo> getUserActivityInfoUpdates();
+    property public final androidx.health.services.client.data.DataPointContainer dataPoints;
+    property public final java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates;
+  }
+
+  public final class SampleDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public SampleDataPoint(androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType, T value, java.time.Duration timeDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> getDataType();
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getTimeDurationFromBoot();
+    method public java.time.Instant getTimeInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration timeDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class StatisticalDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public StatisticalDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.StatisticalDataPoint<T>> dataType, T min, T max, T average, java.time.Instant start, java.time.Instant end);
+    method public T getAverage();
+    method public java.time.Instant getEnd();
+    method public T getMax();
+    method public T getMin();
+    method public java.time.Instant getStart();
+    property public final T average;
+    property public final java.time.Instant end;
+    property public final T max;
+    property public final T min;
+    property public final java.time.Instant start;
+    field public static final androidx.health.services.client.data.StatisticalDataPoint.Companion Companion;
+  }
+
+  public static final class StatisticalDataPoint.Companion {
+  }
+
+  public final class UserActivityInfo {
+    ctor public UserActivityInfo(androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseInfo? exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.ExerciseInfo? getExerciseInfo();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    property public final androidx.health.services.client.data.ExerciseInfo? exerciseInfo;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final androidx.health.services.client.data.UserActivityInfo.Companion Companion;
+  }
+
+  public static final class UserActivityInfo.Companion {
+    method public androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+  }
+
+  public final class UserActivityState {
+    ctor public UserActivityState(int id, String name);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_ASLEEP;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+  }
+
+  public static final class UserActivityState.Companion {
+  }
+
+  public final class WarmUpConfig {
+    ctor public WarmUpConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getDataTypes();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+}
+
diff --git a/health/health-services-client/api/current.ignore b/health/health-services-client/api/current.ignore
deleted file mode 100644
index 091f290..0000000
--- a/health/health-services-client/api/current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AddedAbstractMethod: androidx.health.services.client.ExerciseClient#overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode>):
-    Added method androidx.health.services.client.ExerciseClient.overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode>)
diff --git a/health/health-services-client/api/public_plus_experimental_1.0.0-beta04.txt b/health/health-services-client/api/public_plus_experimental_1.0.0-beta04.txt
new file mode 100644
index 0000000..f2df4c7
--- /dev/null
+++ b/health/health-services-client/api/public_plus_experimental_1.0.0-beta04.txt
@@ -0,0 +1,910 @@
+// Signature format: 4.0
+package androidx.health.services.client {
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateCallbackAsync(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseCapabilities> getCapabilitiesAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfoAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLapAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExerciseAsync(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> prepareExerciseAsync(androidx.health.services.client.data.WarmUpConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> removeGoalFromActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExerciseAsync();
+    method public void setUpdateCallback(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public void setUpdateCallback(java.util.concurrent.Executor executor, androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExerciseAsync(androidx.health.services.client.data.ExerciseConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> updateExerciseTypeConfigAsync(androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig);
+  }
+
+  public final class ExerciseClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? addGoalToActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearUpdateCallback(androidx.health.services.client.ExerciseClient, androidx.health.services.client.ExerciseUpdateCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? endExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCurrentExerciseInfo(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseInfo>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? markLap(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideAutoPauseAndResumeForActiveExercise(androidx.health.services.client.ExerciseClient, boolean enabled, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideBatchingModesForActiveExercise(androidx.health.services.client.ExerciseClient, java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? pauseExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? prepareExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.WarmUpConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? removeGoalFromActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? resumeExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? startExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? updateExerciseTypeConfig(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  public interface ExerciseUpdateCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onExerciseUpdateReceived(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummaryReceived(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+    method public void onRegistered();
+    method public void onRegistrationFailed(Throwable throwable);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public final class HealthServicesException extends java.lang.Exception {
+    ctor public HealthServicesException(String message);
+  }
+
+  public final class ListenableFutureExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend <T> Object? awaitWithException(com.google.common.util.concurrent.ListenableFuture<T>, kotlin.coroutines.Continuation<? super T>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onDataReceived(androidx.health.services.client.data.DataPointContainer data);
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilitiesAsync();
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, java.util.concurrent.Executor executor, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterMeasureCallbackAsync(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+  }
+
+  public final class MeasureClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.MeasureClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.MeasureCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? unregisterMeasureCallback(androidx.health.services.client.MeasureClient, androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface PassiveListenerCallback {
+    method public default void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public default void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public default void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public default void onPermissionLost();
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+    method public default void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public abstract class PassiveListenerService extends android.app.Service {
+    ctor public PassiveListenerService();
+    method public final android.os.IBinder? onBind(android.content.Intent intent);
+    method public void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public void onPermissionLost();
+    method public void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerCallbackAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerServiceAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilitiesAsync();
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, androidx.health.services.client.PassiveListenerCallback callback);
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, java.util.concurrent.Executor executor, androidx.health.services.client.PassiveListenerCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setPassiveListenerServiceAsync(Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config);
+  }
+
+  public final class PassiveMonitoringClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerCallback(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.PassiveMonitoringCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? setPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AggregateDataType<T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public AggregateDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface Availability {
+    method public int getId();
+    property public abstract int id;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+  }
+
+  public final class BatchingMode {
+    field public static final androidx.health.services.client.data.BatchingMode.Companion Companion;
+    field public static final androidx.health.services.client.data.BatchingMode HEART_RATE_5_SECONDS;
+  }
+
+  public static final class BatchingMode.Companion {
+  }
+
+  public final class ComparisonType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType UNKNOWN;
+  }
+
+  public static final class ComparisonType.Companion {
+  }
+
+  public final class CumulativeDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public CumulativeDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.CumulativeDataPoint<T>> dataType, T total, java.time.Instant start, java.time.Instant end);
+    method public java.time.Instant getEnd();
+    method public java.time.Instant getStart();
+    method public T getTotal();
+    property public final java.time.Instant end;
+    property public final java.time.Instant start;
+    property public final T total;
+  }
+
+  public abstract class DataPoint<T> {
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> getDataType();
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> dataType;
+  }
+
+  public abstract class DataPointAccuracy {
+    ctor public DataPointAccuracy();
+  }
+
+  public final class DataPointContainer {
+    ctor public DataPointContainer(java.util.Map<androidx.health.services.client.data.DataType<?,?>,? extends java.util.List<? extends androidx.health.services.client.data.DataPoint<?>>> dataPoints);
+    ctor public DataPointContainer(java.util.List<? extends androidx.health.services.client.data.DataPoint<?>> dataPointList);
+    method public java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> getCumulativeDataPoints();
+    method public <T, D extends androidx.health.services.client.data.DataPoint<T>> java.util.List<D> getData(androidx.health.services.client.data.DeltaDataType<T,D> type);
+    method public <T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> D? getData(androidx.health.services.client.data.AggregateDataType<T,D> type);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> getIntervalDataPoints();
+    method public java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> getSampleDataPoints();
+    method public java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> getStatisticalDataPoints();
+    property public final java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> cumulativeDataPoints;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> intervalDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> sampleDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> statisticalDataPoints;
+  }
+
+  public abstract class DataType<T, D extends androidx.health.services.client.data.DataPoint<T>> {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass, boolean isAggregate);
+    method public final String getName();
+    method public final Class<T> getValueClass();
+    property public final String name;
+    property public final Class<T> valueClass;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> ACTIVE_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> CALORIES_TOTAL;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DECLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> DECLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> DECLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_GAIN;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_GAIN_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_LOSS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_LOSS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> FLAT_GROUND_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> FLAT_GROUND_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLOORS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> GOLF_SHOT_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> GOLF_SHOT_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> HEART_RATE_BPM_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> INCLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> INCLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> INCLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<androidx.health.services.client.data.LocationData,androidx.health.services.client.data.SampleDataPoint<androidx.health.services.client.data.LocationData>> LOCATION;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> PACE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> PACE_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> REP_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> REP_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RUNNING_STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> SPEED;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> SPEED_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS_DAILY;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.SampleDataPoint<java.lang.Long>> STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Long>> STEPS_PER_MINUTE_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> SWIMMING_STROKES_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> VO2_MAX;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> VO2_MAX_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> WALKING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> WALKING_STEPS_TOTAL;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public static final class DataType.TimeType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataType.TimeType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    field public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+    field public static final androidx.health.services.client.data.DataType.TimeType UNKNOWN;
+  }
+
+  public static final class DataType.TimeType.Companion {
+  }
+
+  public final class DataTypeAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataTypeAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.DataTypeAvailability AVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE_DEVICE_OFF_BODY;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNKNOWN;
+  }
+
+  public static final class DataTypeAvailability.Companion {
+    method public androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+  }
+
+  public final class DataTypeCondition<T extends java.lang.Number, D extends androidx.health.services.client.data.DataType<T, ? extends androidx.health.services.client.data.DataPoint<T>>> {
+    ctor public DataTypeCondition(D dataType, T threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public D getDataType();
+    method public T getThreshold();
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final D dataType;
+    property public final T threshold;
+  }
+
+  public final class DeltaDataType<T, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public DeltaDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  public final class ExerciseCapabilities {
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities, optional java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides);
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseTypeCapabilities getExerciseTypeCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getSupportedBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> getTypeToCapabilities();
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities;
+  }
+
+  public final class ExerciseConfig {
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig, optional java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public androidx.health.services.client.data.ExerciseTypeConfig? getExerciseTypeConfig();
+    method public float getSwimmingPoolLengthMeters();
+    method public boolean isAutoPauseAndResumeEnabled();
+    method public boolean isGpsEnabled();
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    property public final androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig;
+    property public final boolean isAutoPauseAndResumeEnabled;
+    property public final boolean isGpsEnabled;
+    property public final float swimmingPoolLengthMeters;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+    field public static final float SWIMMING_POOL_LENGTH_UNSPECIFIED = 0.0f;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setBatchingModeOverrides(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseTypeConfig(androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsAutoPauseAndResumeEnabled(boolean isAutoPauseAndResumeEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsGpsEnabled(boolean isGpsEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setSwimmingPoolLengthMeters(float swimmingPoolLength);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public final class ExerciseGoal<T extends java.lang.Number> implements android.os.Parcelable {
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public T? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final T? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal<?>> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+  }
+
+  public final class ExerciseGoalType {
+    method public static androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    field public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo {
+    ctor public ExerciseInfo(int exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final int exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+  public final class ExerciseLapSummary {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.DataPointContainer lapMetrics);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public androidx.health.services.client.data.DataPointContainer getLapMetrics();
+    method public java.time.Instant getStartTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final androidx.health.services.client.data.DataPointContainer lapMetrics;
+    property public final java.time.Instant startTime;
+  }
+
+  public final class ExerciseState {
+    method public static androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public int getId();
+    method public String getName();
+    method public boolean isEnded();
+    method public boolean isEnding();
+    method public boolean isPaused();
+    method public boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isEnding;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseState ENDED;
+    field public static final androidx.health.services.client.data.ExerciseState ENDING;
+    field public static final androidx.health.services.client.data.ExerciseState PREPARING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public final class ExerciseStateInfo {
+    ctor public ExerciseStateInfo(androidx.health.services.client.data.ExerciseState exerciseState, int exerciseEndReason);
+    method public int getEndReason();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    property public final int endReason;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final androidx.health.services.client.data.ExerciseStateInfo.Companion Companion;
+  }
+
+  public static final class ExerciseStateInfo.Companion {
+  }
+
+  public final class ExerciseType {
+    method public static androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseType ALPINE_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType BACKPACKING;
+    field public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    field public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    field public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    field public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    field public static final androidx.health.services.client.data.ExerciseType BOXING;
+    field public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    field public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    field public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    field public static final androidx.health.services.client.data.ExerciseType CROSS_COUNTRY_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseType DANCING;
+    field public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    field public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    field public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    field public static final androidx.health.services.client.data.ExerciseType FENCING;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    field public static final androidx.health.services.client.data.ExerciseType FORWARD_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    field public static final androidx.health.services.client.data.ExerciseType GOLF;
+    field public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    field public static final androidx.health.services.client.data.ExerciseType GYMNASTICS;
+    field public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    field public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType HIKING;
+    field public static final androidx.health.services.client.data.ExerciseType HORSE_RIDING;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType INLINE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    field public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    field public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    field public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    field public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    field public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    field public static final androidx.health.services.client.data.ExerciseType MOUNTAIN_BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType ORIENTEERING;
+    field public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    field public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    field public static final androidx.health.services.client.data.ExerciseType PILATES;
+    field public static final androidx.health.services.client.data.ExerciseType PLANK;
+    field public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    field public static final androidx.health.services.client.data.ExerciseType SAILING;
+    field public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    field public static final androidx.health.services.client.data.ExerciseType SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    field public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    field public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    field public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    field public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    field public static final androidx.health.services.client.data.ExerciseType SURFING;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    field public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    field public static final androidx.health.services.client.data.ExerciseType UPPER_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    field public static final androidx.health.services.client.data.ExerciseType WALKING;
+    field public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    field public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    field public static final androidx.health.services.client.data.ExerciseType WORKOUT;
+    field public static final androidx.health.services.client.data.ExerciseType YACHTING;
+    field public static final androidx.health.services.client.data.ExerciseType YOGA;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseTypeCapabilities {
+    ctor public ExerciseTypeCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypes, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+  }
+
+  public abstract class ExerciseTypeConfig {
+    field public static final androidx.health.services.client.data.ExerciseTypeConfig.Companion Companion;
+  }
+
+  public static final class ExerciseTypeConfig.Companion {
+  }
+
+  public final class ExerciseUpdate {
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.IntervalDataPoint<?> dataPoint);
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.SampleDataPoint<?> dataPoint);
+    method public androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? getActiveDurationCheckpoint();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseStateInfo getExerciseStateInfo();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> getLatestAchievedGoals();
+    method public androidx.health.services.client.data.DataPointContainer getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant? getStartTime();
+    method public java.time.Duration getUpdateDurationFromBoot();
+    property public final androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? activeDurationCheckpoint;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseStateInfo exerciseStateInfo;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> latestAchievedGoals;
+    property public final androidx.health.services.client.data.DataPointContainer latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant? startTime;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.ActiveDurationCheckpoint {
+    ctor public ExerciseUpdate.ActiveDurationCheckpoint(java.time.Instant time, java.time.Duration activeDuration);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant time;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public final class GolfExerciseTypeConfig extends androidx.health.services.client.data.ExerciseTypeConfig {
+    ctor public GolfExerciseTypeConfig(optional androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo);
+    method public androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo getGolfShotTrackingPlaceInfo();
+    property public final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo {
+    method public int getPlaceInfoId();
+    property public final int placeInfoId;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion Companion;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_FAIRWAY;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_PUTTING_GREEN;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_TEE_BOX;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_UNSPECIFIED;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion {
+  }
+
+  public final class HealthEvent {
+    ctor public HealthEvent(androidx.health.services.client.data.HealthEvent.Type type, java.time.Instant eventTime, androidx.health.services.client.data.DataPointContainer metrics);
+    method public java.time.Instant getEventTime();
+    method public androidx.health.services.client.data.DataPointContainer getMetrics();
+    method public androidx.health.services.client.data.HealthEvent.Type getType();
+    property public final java.time.Instant eventTime;
+    property public final androidx.health.services.client.data.DataPointContainer metrics;
+    property public final androidx.health.services.client.data.HealthEvent.Type type;
+  }
+
+  public static final class HealthEvent.Type {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HealthEvent.Type.Companion Companion;
+    field public static final androidx.health.services.client.data.HealthEvent.Type FALL_DETECTED;
+    field public static final androidx.health.services.client.data.HealthEvent.Type UNKNOWN;
+  }
+
+  public static final class HealthEvent.Type.Companion {
+  }
+
+  public final class HeartRateAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public HeartRateAccuracy(androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus);
+    method public androidx.health.services.client.data.HeartRateAccuracy.SensorStatus getSensorStatus();
+    property public final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_HIGH;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_LOW;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_MEDIUM;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus.Companion Companion;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus NO_CONTACT;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNKNOWN;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNRELIABLE;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus.Companion {
+  }
+
+  public final class IntervalDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public IntervalDataPoint(androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType, T value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class LocationAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public LocationAccuracy(@FloatRange(from=0.0) double horizontalPositionErrorMeters, optional @FloatRange(from=0.0) double verticalPositionErrorMeters);
+    method public double getHorizontalPositionErrorMeters();
+    method public double getVerticalPositionErrorMeters();
+    property public final double horizontalPositionErrorMeters;
+    property public final double verticalPositionErrorMeters;
+    field public static final androidx.health.services.client.data.LocationAccuracy.Companion Companion;
+  }
+
+  public static final class LocationAccuracy.Companion {
+  }
+
+  public final class LocationAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.LocationAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_TETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_UNTETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.LocationAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.LocationAvailability NO_GNSS;
+    field public static final androidx.health.services.client.data.LocationAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.LocationAvailability UNKNOWN;
+  }
+
+  public static final class LocationAvailability.Companion {
+    method public androidx.health.services.client.data.LocationAvailability? fromId(int id);
+  }
+
+  public final class LocationData {
+    ctor public LocationData(@FloatRange(from=-90.0, to=90.0) double latitude, @FloatRange(from=-180.0, to=180.0) double longitude, optional double altitude, optional double bearing);
+    method public double getAltitude();
+    method public double getBearing();
+    method public double getLatitude();
+    method public double getLongitude();
+    property public final double altitude;
+    property public final double bearing;
+    property public final double latitude;
+    property public final double longitude;
+    field public static final double ALTITUDE_UNAVAILABLE = (0.0/0.0);
+    field public static final double BEARING_UNAVAILABLE = (0.0/0.0);
+  }
+
+  public final class MeasureCapabilities {
+    ctor public MeasureCapabilities(java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getSupportedDataTypesMeasure();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure;
+  }
+
+  public final class MilestoneMarkerSummary {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal, androidx.health.services.client.data.DataPointContainer summaryMetrics);
+    method public androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.DataPointContainer getSummaryMetrics();
+    property public final androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.DataPointContainer summaryMetrics;
+  }
+
+  public final class PassiveGoal {
+    ctor public PassiveGoal(androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition);
+    method public androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> getDataTypeCondition();
+    property public final androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition;
+  }
+
+  public final class PassiveListenerConfig {
+    ctor public PassiveListenerConfig(java.util.Set<? extends androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes, boolean shouldUserActivityInfoBeRequested, java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public static androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+    method public java.util.Set<androidx.health.services.client.data.PassiveGoal> getDailyGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> getDataTypes();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getHealthEventTypes();
+    method public boolean getShouldUserActivityInfoBeRequested();
+    property public final java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes;
+    property public final boolean shouldUserActivityInfoBeRequested;
+    field public static final androidx.health.services.client.data.PassiveListenerConfig.Companion Companion;
+  }
+
+  public static final class PassiveListenerConfig.Builder {
+    ctor public PassiveListenerConfig.Builder();
+    method public androidx.health.services.client.data.PassiveListenerConfig build();
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDailyGoals(java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setHealthEventTypes(java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setShouldUserActivityInfoBeRequested(boolean shouldUserActivityInfoBeRequested);
+  }
+
+  public static final class PassiveListenerConfig.Companion {
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+  }
+
+  public final class PassiveMonitoringCapabilities {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes, java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveMonitoring();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getSupportedHealthEventTypes();
+    method public java.util.Set<androidx.health.services.client.data.UserActivityState> getSupportedUserActivityStates();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes;
+    property public final java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates;
+  }
+
+  public final class PassiveMonitoringUpdate {
+    ctor public PassiveMonitoringUpdate(androidx.health.services.client.data.DataPointContainer dataPoints, java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates);
+    method public androidx.health.services.client.data.DataPointContainer getDataPoints();
+    method public java.util.List<androidx.health.services.client.data.UserActivityInfo> getUserActivityInfoUpdates();
+    property public final androidx.health.services.client.data.DataPointContainer dataPoints;
+    property public final java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates;
+  }
+
+  public final class SampleDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public SampleDataPoint(androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType, T value, java.time.Duration timeDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> getDataType();
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getTimeDurationFromBoot();
+    method public java.time.Instant getTimeInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration timeDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class StatisticalDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public StatisticalDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.StatisticalDataPoint<T>> dataType, T min, T max, T average, java.time.Instant start, java.time.Instant end);
+    method public T getAverage();
+    method public java.time.Instant getEnd();
+    method public T getMax();
+    method public T getMin();
+    method public java.time.Instant getStart();
+    property public final T average;
+    property public final java.time.Instant end;
+    property public final T max;
+    property public final T min;
+    property public final java.time.Instant start;
+    field public static final androidx.health.services.client.data.StatisticalDataPoint.Companion Companion;
+  }
+
+  public static final class StatisticalDataPoint.Companion {
+  }
+
+  public final class UserActivityInfo {
+    ctor public UserActivityInfo(androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseInfo? exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.ExerciseInfo? getExerciseInfo();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    property public final androidx.health.services.client.data.ExerciseInfo? exerciseInfo;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final androidx.health.services.client.data.UserActivityInfo.Companion Companion;
+  }
+
+  public static final class UserActivityInfo.Companion {
+    method public androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+  }
+
+  public final class UserActivityState {
+    ctor public UserActivityState(int id, String name);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_ASLEEP;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+  }
+
+  public static final class UserActivityState.Companion {
+  }
+
+  public final class WarmUpConfig {
+    ctor public WarmUpConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getDataTypes();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+}
+
diff --git a/health/health-services-client/api/res-1.0.0-beta04.txt b/health/health-services-client/api/res-1.0.0-beta04.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/health/health-services-client/api/res-1.0.0-beta04.txt
diff --git a/health/health-services-client/api/restricted_1.0.0-beta04.txt b/health/health-services-client/api/restricted_1.0.0-beta04.txt
new file mode 100644
index 0000000..f2df4c7
--- /dev/null
+++ b/health/health-services-client/api/restricted_1.0.0-beta04.txt
@@ -0,0 +1,910 @@
+// Signature format: 4.0
+package androidx.health.services.client {
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface ExerciseClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> addGoalToActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearUpdateCallbackAsync(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> endExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseCapabilities> getCapabilitiesAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.ExerciseInfo> getCurrentExerciseInfoAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> markLapAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideAutoPauseAndResumeForActiveExerciseAsync(boolean enabled);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> pauseExerciseAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> prepareExerciseAsync(androidx.health.services.client.data.WarmUpConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> removeGoalFromActiveExerciseAsync(androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> resumeExerciseAsync();
+    method public void setUpdateCallback(androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public void setUpdateCallback(java.util.concurrent.Executor executor, androidx.health.services.client.ExerciseUpdateCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> startExerciseAsync(androidx.health.services.client.data.ExerciseConfig configuration);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> updateExerciseTypeConfigAsync(androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig);
+  }
+
+  public final class ExerciseClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? addGoalToActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearUpdateCallback(androidx.health.services.client.ExerciseClient, androidx.health.services.client.ExerciseUpdateCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? endExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCurrentExerciseInfo(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.ExerciseInfo>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? markLap(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideAutoPauseAndResumeForActiveExercise(androidx.health.services.client.ExerciseClient, boolean enabled, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? overrideBatchingModesForActiveExercise(androidx.health.services.client.ExerciseClient, java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModes, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? pauseExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? prepareExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.WarmUpConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? removeGoalFromActiveExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseGoal<?> exerciseGoal, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? resumeExercise(androidx.health.services.client.ExerciseClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? startExercise(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseConfig configuration, kotlin.coroutines.Continuation<? super kotlin.Unit>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? updateExerciseTypeConfig(androidx.health.services.client.ExerciseClient, androidx.health.services.client.data.ExerciseTypeConfig exerciseTypeConfig, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  public interface ExerciseUpdateCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onExerciseUpdateReceived(androidx.health.services.client.data.ExerciseUpdate update);
+    method public void onLapSummaryReceived(androidx.health.services.client.data.ExerciseLapSummary lapSummary);
+    method public void onRegistered();
+    method public void onRegistrationFailed(Throwable throwable);
+  }
+
+  public final class HealthServices {
+    method public static androidx.health.services.client.HealthServicesClient getClient(android.content.Context context);
+    field public static final androidx.health.services.client.HealthServices INSTANCE;
+  }
+
+  public interface HealthServicesClient {
+    method public androidx.health.services.client.ExerciseClient getExerciseClient();
+    method public androidx.health.services.client.MeasureClient getMeasureClient();
+    method public androidx.health.services.client.PassiveMonitoringClient getPassiveMonitoringClient();
+    property public abstract androidx.health.services.client.ExerciseClient exerciseClient;
+    property public abstract androidx.health.services.client.MeasureClient measureClient;
+    property public abstract androidx.health.services.client.PassiveMonitoringClient passiveMonitoringClient;
+  }
+
+  public final class HealthServicesException extends java.lang.Exception {
+    ctor public HealthServicesException(String message);
+  }
+
+  public final class ListenableFutureExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend <T> Object? awaitWithException(com.google.common.util.concurrent.ListenableFuture<T>, kotlin.coroutines.Continuation<? super T>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface MeasureCallback {
+    method public void onAvailabilityChanged(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.data.Availability availability);
+    method public void onDataReceived(androidx.health.services.client.data.DataPointContainer data);
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+  }
+
+  public interface MeasureClient {
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.MeasureCapabilities> getCapabilitiesAsync();
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+    method public void registerMeasureCallback(androidx.health.services.client.data.DeltaDataType<?,?> dataType, java.util.concurrent.Executor executor, androidx.health.services.client.MeasureCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> unregisterMeasureCallbackAsync(androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback);
+  }
+
+  public final class MeasureClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.MeasureClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.MeasureCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? unregisterMeasureCallback(androidx.health.services.client.MeasureClient, androidx.health.services.client.data.DeltaDataType<?,?> dataType, androidx.health.services.client.MeasureCallback callback, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface PassiveListenerCallback {
+    method public default void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public default void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public default void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public default void onPermissionLost();
+    method public default void onRegistered();
+    method public default void onRegistrationFailed(Throwable throwable);
+    method public default void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public abstract class PassiveListenerService extends android.app.Service {
+    ctor public PassiveListenerService();
+    method public final android.os.IBinder? onBind(android.content.Intent intent);
+    method public void onGoalCompleted(androidx.health.services.client.data.PassiveGoal goal);
+    method public void onHealthEventReceived(androidx.health.services.client.data.HealthEvent event);
+    method public void onNewDataPointsReceived(androidx.health.services.client.data.DataPointContainer dataPoints);
+    method public void onPermissionLost();
+    method public void onUserActivityInfoReceived(androidx.health.services.client.data.UserActivityInfo info);
+  }
+
+  public interface PassiveMonitoringClient {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerCallbackAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> clearPassiveListenerServiceAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> flushAsync();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.health.services.client.data.PassiveMonitoringCapabilities> getCapabilitiesAsync();
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, androidx.health.services.client.PassiveListenerCallback callback);
+    method public void setPassiveListenerCallback(androidx.health.services.client.data.PassiveListenerConfig config, java.util.concurrent.Executor executor, androidx.health.services.client.PassiveListenerCallback callback);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void> setPassiveListenerServiceAsync(Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config);
+  }
+
+  public final class PassiveMonitoringClientExtensionKt {
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerCallback(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? clearPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? flush(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? getCapabilities(androidx.health.services.client.PassiveMonitoringClient, kotlin.coroutines.Continuation<? super androidx.health.services.client.data.PassiveMonitoringCapabilities>) throws androidx.health.services.client.HealthServicesException;
+    method @kotlin.jvm.Throws(exceptionClasses=HealthServicesException::class) public static suspend Object? setPassiveListenerService(androidx.health.services.client.PassiveMonitoringClient, Class<? extends androidx.health.services.client.PassiveListenerService> service, androidx.health.services.client.data.PassiveListenerConfig config, kotlin.coroutines.Continuation<? super java.lang.Void>) throws androidx.health.services.client.HealthServicesException;
+  }
+
+}
+
+package androidx.health.services.client.data {
+
+  public final class AggregateDataType<T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public AggregateDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface Availability {
+    method public int getId();
+    property public abstract int id;
+    field public static final androidx.health.services.client.data.Availability.Companion Companion;
+  }
+
+  public static final class Availability.Companion {
+  }
+
+  public final class BatchingMode {
+    field public static final androidx.health.services.client.data.BatchingMode.Companion Companion;
+    field public static final androidx.health.services.client.data.BatchingMode HEART_RATE_5_SECONDS;
+  }
+
+  public static final class BatchingMode.Companion {
+  }
+
+  public final class ComparisonType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ComparisonType.Companion Companion;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType GREATER_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN;
+    field public static final androidx.health.services.client.data.ComparisonType LESS_THAN_OR_EQUAL;
+    field public static final androidx.health.services.client.data.ComparisonType UNKNOWN;
+  }
+
+  public static final class ComparisonType.Companion {
+  }
+
+  public final class CumulativeDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public CumulativeDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.CumulativeDataPoint<T>> dataType, T total, java.time.Instant start, java.time.Instant end);
+    method public java.time.Instant getEnd();
+    method public java.time.Instant getStart();
+    method public T getTotal();
+    property public final java.time.Instant end;
+    property public final java.time.Instant start;
+    property public final T total;
+  }
+
+  public abstract class DataPoint<T> {
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> getDataType();
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.DataPoint<T>> dataType;
+  }
+
+  public abstract class DataPointAccuracy {
+    ctor public DataPointAccuracy();
+  }
+
+  public final class DataPointContainer {
+    ctor public DataPointContainer(java.util.Map<androidx.health.services.client.data.DataType<?,?>,? extends java.util.List<? extends androidx.health.services.client.data.DataPoint<?>>> dataPoints);
+    ctor public DataPointContainer(java.util.List<? extends androidx.health.services.client.data.DataPoint<?>> dataPointList);
+    method public java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> getCumulativeDataPoints();
+    method public <T, D extends androidx.health.services.client.data.DataPoint<T>> java.util.List<D> getData(androidx.health.services.client.data.DeltaDataType<T,D> type);
+    method public <T extends java.lang.Number, D extends androidx.health.services.client.data.DataPoint<T>> D? getData(androidx.health.services.client.data.AggregateDataType<T,D> type);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> getIntervalDataPoints();
+    method public java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> getSampleDataPoints();
+    method public java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> getStatisticalDataPoints();
+    property public final java.util.List<androidx.health.services.client.data.CumulativeDataPoint<?>> cumulativeDataPoints;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.IntervalDataPoint<?>> intervalDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.SampleDataPoint<?>> sampleDataPoints;
+    property public final java.util.List<androidx.health.services.client.data.StatisticalDataPoint<?>> statisticalDataPoints;
+  }
+
+  public abstract class DataType<T, D extends androidx.health.services.client.data.DataPoint<T>> {
+    ctor public DataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass, boolean isAggregate);
+    method public final String getName();
+    method public final Class<T> getValueClass();
+    property public final String name;
+    property public final Class<T> valueClass;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> ABSOLUTE_ELEVATION_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> ACTIVE_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> CALORIES_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> CALORIES_TOTAL;
+    field public static final androidx.health.services.client.data.DataType.Companion Companion;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DECLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DECLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> DECLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> DECLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> DISTANCE_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_GAIN;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_GAIN_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> ELEVATION_LOSS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> ELEVATION_LOSS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLAT_GROUND_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> FLAT_GROUND_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> FLAT_GROUND_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> FLOORS_DAILY;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> FLOORS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> GOLF_SHOT_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> GOLF_SHOT_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> HEART_RATE_BPM;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> HEART_RATE_BPM_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.IntervalDataPoint<java.lang.Double>> INCLINE_DISTANCE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Double>> INCLINE_DISTANCE_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> INCLINE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> INCLINE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<androidx.health.services.client.data.LocationData,androidx.health.services.client.data.SampleDataPoint<androidx.health.services.client.data.LocationData>> LOCATION;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> PACE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> PACE_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> REP_COUNT;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> REP_COUNT_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RESTING_EXERCISE_DURATION_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> RUNNING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> RUNNING_STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> SPEED;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> SPEED_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> STEPS_DAILY;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.SampleDataPoint<java.lang.Long>> STEPS_PER_MINUTE;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Long>> STEPS_PER_MINUTE_STATS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> STEPS_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_LAP_COUNT;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> SWIMMING_STROKES;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> SWIMMING_STROKES_TOTAL;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Double,androidx.health.services.client.data.SampleDataPoint<java.lang.Double>> VO2_MAX;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Double,androidx.health.services.client.data.StatisticalDataPoint<java.lang.Double>> VO2_MAX_STATS;
+    field public static final androidx.health.services.client.data.DeltaDataType<java.lang.Long,androidx.health.services.client.data.IntervalDataPoint<java.lang.Long>> WALKING_STEPS;
+    field public static final androidx.health.services.client.data.AggregateDataType<java.lang.Long,androidx.health.services.client.data.CumulativeDataPoint<java.lang.Long>> WALKING_STEPS_TOTAL;
+  }
+
+  public static final class DataType.Companion {
+  }
+
+  public static final class DataType.TimeType {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataType.TimeType.Companion Companion;
+    field public static final androidx.health.services.client.data.DataType.TimeType INTERVAL;
+    field public static final androidx.health.services.client.data.DataType.TimeType SAMPLE;
+    field public static final androidx.health.services.client.data.DataType.TimeType UNKNOWN;
+  }
+
+  public static final class DataType.TimeType.Companion {
+  }
+
+  public final class DataTypeAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.DataTypeAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.DataTypeAvailability AVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNAVAILABLE_DEVICE_OFF_BODY;
+    field public static final androidx.health.services.client.data.DataTypeAvailability UNKNOWN;
+  }
+
+  public static final class DataTypeAvailability.Companion {
+    method public androidx.health.services.client.data.DataTypeAvailability? fromId(int id);
+  }
+
+  public final class DataTypeCondition<T extends java.lang.Number, D extends androidx.health.services.client.data.DataType<T, ? extends androidx.health.services.client.data.DataPoint<T>>> {
+    ctor public DataTypeCondition(D dataType, T threshold, androidx.health.services.client.data.ComparisonType comparisonType);
+    method public androidx.health.services.client.data.ComparisonType getComparisonType();
+    method public D getDataType();
+    method public T getThreshold();
+    property public final androidx.health.services.client.data.ComparisonType comparisonType;
+    property public final D dataType;
+    property public final T threshold;
+  }
+
+  public final class DeltaDataType<T, D extends androidx.health.services.client.data.DataPoint<T>> extends androidx.health.services.client.data.DataType<T,D> {
+    ctor public DeltaDataType(String name, androidx.health.services.client.data.DataType.TimeType timeType, Class<T> valueClass);
+  }
+
+  public final class ExerciseCapabilities {
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities, optional java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides);
+    ctor public ExerciseCapabilities(java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities);
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getAutoPauseAndResumeEnabledExercises();
+    method public androidx.health.services.client.data.ExerciseTypeCapabilities getExerciseTypeCapabilities(androidx.health.services.client.data.ExerciseType exercise);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getSupportedBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseType> getSupportedExerciseTypes();
+    method public java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> getTypeToCapabilities();
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> autoPauseAndResumeEnabledExercises;
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> supportedBatchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseType> supportedExerciseTypes;
+    property public final java.util.Map<androidx.health.services.client.data.ExerciseType,androidx.health.services.client.data.ExerciseTypeCapabilities> typeToCapabilities;
+  }
+
+  public final class ExerciseConfig {
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig, optional java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters, optional androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    ctor public ExerciseConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes, boolean isAutoPauseAndResumeEnabled, boolean isGpsEnabled, optional java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals, optional android.os.Bundle exerciseParams, optional @FloatRange(from=0.0) float swimmingPoolLengthMeters);
+    method public static androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public java.util.Set<androidx.health.services.client.data.BatchingMode> getBatchingModeOverrides();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getDataTypes();
+    method public java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> getExerciseGoals();
+    method public android.os.Bundle getExerciseParams();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    method public androidx.health.services.client.data.ExerciseTypeConfig? getExerciseTypeConfig();
+    method public float getSwimmingPoolLengthMeters();
+    method public boolean isAutoPauseAndResumeEnabled();
+    method public boolean isGpsEnabled();
+    property public final java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> dataTypes;
+    property public final java.util.List<androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals;
+    property public final android.os.Bundle exerciseParams;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+    property public final androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig;
+    property public final boolean isAutoPauseAndResumeEnabled;
+    property public final boolean isGpsEnabled;
+    property public final float swimmingPoolLengthMeters;
+    field public static final androidx.health.services.client.data.ExerciseConfig.Companion Companion;
+    field public static final float SWIMMING_POOL_LENGTH_UNSPECIFIED = 0.0f;
+  }
+
+  public static final class ExerciseConfig.Builder {
+    ctor public ExerciseConfig.Builder(androidx.health.services.client.data.ExerciseType exerciseType);
+    method public androidx.health.services.client.data.ExerciseConfig build();
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setBatchingModeOverrides(java.util.Set<androidx.health.services.client.data.BatchingMode> batchingModeOverrides);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseGoals(java.util.List<? extends androidx.health.services.client.data.ExerciseGoal<?>> exerciseGoals);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseParams(android.os.Bundle exerciseParams);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setExerciseTypeConfig(androidx.health.services.client.data.ExerciseTypeConfig? exerciseTypeConfig);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsAutoPauseAndResumeEnabled(boolean isAutoPauseAndResumeEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setIsGpsEnabled(boolean isGpsEnabled);
+    method public androidx.health.services.client.data.ExerciseConfig.Builder setSwimmingPoolLengthMeters(float swimmingPoolLength);
+  }
+
+  public static final class ExerciseConfig.Companion {
+    method public androidx.health.services.client.data.ExerciseConfig.Builder builder(androidx.health.services.client.data.ExerciseType exerciseType);
+  }
+
+  public final class ExerciseGoal<T extends java.lang.Number> implements android.os.Parcelable {
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public static <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+    method public int describeContents();
+    method public androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> getDataTypeCondition();
+    method public androidx.health.services.client.data.ExerciseGoalType getExerciseGoalType();
+    method public T? getPeriod();
+    method public void writeToParcel(android.os.Parcel dest, int flags);
+    property public final androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> dataTypeCondition;
+    property public final androidx.health.services.client.data.ExerciseGoalType exerciseGoalType;
+    property public final T? period;
+    field public static final android.os.Parcelable.Creator<androidx.health.services.client.data.ExerciseGoal<?>> CREATOR;
+    field public static final androidx.health.services.client.data.ExerciseGoal.Companion Companion;
+  }
+
+  public static final class ExerciseGoal.Companion {
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestone(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition, T period);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createMilestoneGoalWithUpdatedThreshold(androidx.health.services.client.data.ExerciseGoal<T> goal, T newThreshold);
+    method public <T extends java.lang.Number> androidx.health.services.client.data.ExerciseGoal<T> createOneTimeGoal(androidx.health.services.client.data.DataTypeCondition<T,androidx.health.services.client.data.AggregateDataType<T,?>> condition);
+  }
+
+  public final class ExerciseGoalType {
+    method public static androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseGoalType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseGoalType MILESTONE;
+    field public static final androidx.health.services.client.data.ExerciseGoalType ONE_TIME_GOAL;
+  }
+
+  public static final class ExerciseGoalType.Companion {
+    method public androidx.health.services.client.data.ExerciseGoalType? fromId(int id);
+  }
+
+  public final class ExerciseInfo {
+    ctor public ExerciseInfo(int exerciseTrackedStatus, androidx.health.services.client.data.ExerciseType exerciseType);
+    method public int getExerciseTrackedStatus();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final int exerciseTrackedStatus;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+  public final class ExerciseLapSummary {
+    ctor public ExerciseLapSummary(int lapCount, java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.DataPointContainer lapMetrics);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public int getLapCount();
+    method public androidx.health.services.client.data.DataPointContainer getLapMetrics();
+    method public java.time.Instant getStartTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final int lapCount;
+    property public final androidx.health.services.client.data.DataPointContainer lapMetrics;
+    property public final java.time.Instant startTime;
+  }
+
+  public final class ExerciseState {
+    method public static androidx.health.services.client.data.ExerciseState? fromId(int id);
+    method public int getId();
+    method public String getName();
+    method public boolean isEnded();
+    method public boolean isEnding();
+    method public boolean isPaused();
+    method public boolean isResuming();
+    property public final int id;
+    property public final boolean isEnded;
+    property public final boolean isEnding;
+    property public final boolean isPaused;
+    property public final boolean isResuming;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseState ACTIVE;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState AUTO_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseState ENDED;
+    field public static final androidx.health.services.client.data.ExerciseState ENDING;
+    field public static final androidx.health.services.client.data.ExerciseState PREPARING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSED;
+    field public static final androidx.health.services.client.data.ExerciseState USER_PAUSING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_RESUMING;
+    field public static final androidx.health.services.client.data.ExerciseState USER_STARTING;
+  }
+
+  public static final class ExerciseState.Companion {
+    method public androidx.health.services.client.data.ExerciseState? fromId(int id);
+  }
+
+  public final class ExerciseStateInfo {
+    ctor public ExerciseStateInfo(androidx.health.services.client.data.ExerciseState exerciseState, int exerciseEndReason);
+    method public int getEndReason();
+    method public androidx.health.services.client.data.ExerciseState getState();
+    property public final int endReason;
+    property public final androidx.health.services.client.data.ExerciseState state;
+    field public static final androidx.health.services.client.data.ExerciseStateInfo.Companion Companion;
+  }
+
+  public static final class ExerciseStateInfo.Companion {
+  }
+
+  public final class ExerciseType {
+    method public static androidx.health.services.client.data.ExerciseType fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.ExerciseType ALPINE_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType BACKPACKING;
+    field public static final androidx.health.services.client.data.ExerciseType BACK_EXTENSION;
+    field public static final androidx.health.services.client.data.ExerciseType BADMINTON;
+    field public static final androidx.health.services.client.data.ExerciseType BARBELL_SHOULDER_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BASEBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BASKETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType BENCH_PRESS;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType BIKING_STATIONARY;
+    field public static final androidx.health.services.client.data.ExerciseType BOOT_CAMP;
+    field public static final androidx.health.services.client.data.ExerciseType BOXING;
+    field public static final androidx.health.services.client.data.ExerciseType BURPEE;
+    field public static final androidx.health.services.client.data.ExerciseType CALISTHENICS;
+    field public static final androidx.health.services.client.data.ExerciseType CRICKET;
+    field public static final androidx.health.services.client.data.ExerciseType CROSS_COUNTRY_SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType CRUNCH;
+    field public static final androidx.health.services.client.data.ExerciseType.Companion Companion;
+    field public static final androidx.health.services.client.data.ExerciseType DANCING;
+    field public static final androidx.health.services.client.data.ExerciseType DEADLIFT;
+    field public static final androidx.health.services.client.data.ExerciseType ELLIPTICAL;
+    field public static final androidx.health.services.client.data.ExerciseType EXERCISE_CLASS;
+    field public static final androidx.health.services.client.data.ExerciseType FENCING;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AMERICAN;
+    field public static final androidx.health.services.client.data.ExerciseType FOOTBALL_AUSTRALIAN;
+    field public static final androidx.health.services.client.data.ExerciseType FORWARD_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType FRISBEE_DISC;
+    field public static final androidx.health.services.client.data.ExerciseType GOLF;
+    field public static final androidx.health.services.client.data.ExerciseType GUIDED_BREATHING;
+    field public static final androidx.health.services.client.data.ExerciseType GYMNASTICS;
+    field public static final androidx.health.services.client.data.ExerciseType HANDBALL;
+    field public static final androidx.health.services.client.data.ExerciseType HIGH_INTENSITY_INTERVAL_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType HIKING;
+    field public static final androidx.health.services.client.data.ExerciseType HORSE_RIDING;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ICE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType INLINE_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType JUMPING_JACK;
+    field public static final androidx.health.services.client.data.ExerciseType JUMP_ROPE;
+    field public static final androidx.health.services.client.data.ExerciseType LAT_PULL_DOWN;
+    field public static final androidx.health.services.client.data.ExerciseType LUNGE;
+    field public static final androidx.health.services.client.data.ExerciseType MARTIAL_ARTS;
+    field public static final androidx.health.services.client.data.ExerciseType MEDITATION;
+    field public static final androidx.health.services.client.data.ExerciseType MOUNTAIN_BIKING;
+    field public static final androidx.health.services.client.data.ExerciseType ORIENTEERING;
+    field public static final androidx.health.services.client.data.ExerciseType PADDLING;
+    field public static final androidx.health.services.client.data.ExerciseType PARA_GLIDING;
+    field public static final androidx.health.services.client.data.ExerciseType PILATES;
+    field public static final androidx.health.services.client.data.ExerciseType PLANK;
+    field public static final androidx.health.services.client.data.ExerciseType RACQUETBALL;
+    field public static final androidx.health.services.client.data.ExerciseType ROCK_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_HOCKEY;
+    field public static final androidx.health.services.client.data.ExerciseType ROLLER_SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING;
+    field public static final androidx.health.services.client.data.ExerciseType ROWING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType RUGBY;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING;
+    field public static final androidx.health.services.client.data.ExerciseType RUNNING_TREADMILL;
+    field public static final androidx.health.services.client.data.ExerciseType SAILING;
+    field public static final androidx.health.services.client.data.ExerciseType SCUBA_DIVING;
+    field public static final androidx.health.services.client.data.ExerciseType SKATING;
+    field public static final androidx.health.services.client.data.ExerciseType SKIING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWBOARDING;
+    field public static final androidx.health.services.client.data.ExerciseType SNOWSHOEING;
+    field public static final androidx.health.services.client.data.ExerciseType SOCCER;
+    field public static final androidx.health.services.client.data.ExerciseType SOFTBALL;
+    field public static final androidx.health.services.client.data.ExerciseType SQUASH;
+    field public static final androidx.health.services.client.data.ExerciseType SQUAT;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING;
+    field public static final androidx.health.services.client.data.ExerciseType STAIR_CLIMBING_MACHINE;
+    field public static final androidx.health.services.client.data.ExerciseType STRENGTH_TRAINING;
+    field public static final androidx.health.services.client.data.ExerciseType STRETCHING;
+    field public static final androidx.health.services.client.data.ExerciseType SURFING;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_OPEN_WATER;
+    field public static final androidx.health.services.client.data.ExerciseType SWIMMING_POOL;
+    field public static final androidx.health.services.client.data.ExerciseType TABLE_TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType TENNIS;
+    field public static final androidx.health.services.client.data.ExerciseType UNKNOWN;
+    field public static final androidx.health.services.client.data.ExerciseType UPPER_TWIST;
+    field public static final androidx.health.services.client.data.ExerciseType VOLLEYBALL;
+    field public static final androidx.health.services.client.data.ExerciseType WALKING;
+    field public static final androidx.health.services.client.data.ExerciseType WATER_POLO;
+    field public static final androidx.health.services.client.data.ExerciseType WEIGHTLIFTING;
+    field public static final androidx.health.services.client.data.ExerciseType WORKOUT;
+    field public static final androidx.health.services.client.data.ExerciseType YACHTING;
+    field public static final androidx.health.services.client.data.ExerciseType YOGA;
+  }
+
+  public static final class ExerciseType.Companion {
+    method public androidx.health.services.client.data.ExerciseType fromId(int id);
+  }
+
+  public final class ExerciseTypeCapabilities {
+    ctor public ExerciseTypeCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypes, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals, java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,? extends java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones, boolean supportsAutoPauseAndResume);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypes();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedGoals();
+    method public java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> getSupportedMilestones();
+    method public boolean getSupportsAutoPauseAndResume();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypes;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedGoals;
+    property public final java.util.Map<androidx.health.services.client.data.AggregateDataType<?,?>,java.util.Set<androidx.health.services.client.data.ComparisonType>> supportedMilestones;
+    property public final boolean supportsAutoPauseAndResume;
+  }
+
+  public abstract class ExerciseTypeConfig {
+    field public static final androidx.health.services.client.data.ExerciseTypeConfig.Companion Companion;
+  }
+
+  public static final class ExerciseTypeConfig.Companion {
+  }
+
+  public final class ExerciseUpdate {
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.IntervalDataPoint<?> dataPoint);
+    method public java.time.Duration getActiveDurationAtDataPoint(androidx.health.services.client.data.SampleDataPoint<?> dataPoint);
+    method public androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? getActiveDurationCheckpoint();
+    method public androidx.health.services.client.data.ExerciseConfig? getExerciseConfig();
+    method public androidx.health.services.client.data.ExerciseStateInfo getExerciseStateInfo();
+    method public java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> getLatestAchievedGoals();
+    method public androidx.health.services.client.data.DataPointContainer getLatestMetrics();
+    method public java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> getLatestMilestoneMarkerSummaries();
+    method public java.time.Instant? getStartTime();
+    method public java.time.Duration getUpdateDurationFromBoot();
+    property public final androidx.health.services.client.data.ExerciseUpdate.ActiveDurationCheckpoint? activeDurationCheckpoint;
+    property public final androidx.health.services.client.data.ExerciseConfig? exerciseConfig;
+    property public final androidx.health.services.client.data.ExerciseStateInfo exerciseStateInfo;
+    property public final java.util.Set<androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number>> latestAchievedGoals;
+    property public final androidx.health.services.client.data.DataPointContainer latestMetrics;
+    property public final java.util.Set<androidx.health.services.client.data.MilestoneMarkerSummary> latestMilestoneMarkerSummaries;
+    property public final java.time.Instant? startTime;
+    field public static final androidx.health.services.client.data.ExerciseUpdate.Companion Companion;
+  }
+
+  public static final class ExerciseUpdate.ActiveDurationCheckpoint {
+    ctor public ExerciseUpdate.ActiveDurationCheckpoint(java.time.Instant time, java.time.Duration activeDuration);
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getTime();
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant time;
+  }
+
+  public static final class ExerciseUpdate.Companion {
+  }
+
+  public final class GolfExerciseTypeConfig extends androidx.health.services.client.data.ExerciseTypeConfig {
+    ctor public GolfExerciseTypeConfig(optional androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo);
+    method public androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo getGolfShotTrackingPlaceInfo();
+    property public final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo golfShotTrackingPlaceInfo;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo {
+    method public int getPlaceInfoId();
+    property public final int placeInfoId;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion Companion;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_FAIRWAY;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_PUTTING_GREEN;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_TEE_BOX;
+    field public static final androidx.health.services.client.data.GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo GOLF_SHOT_TRACKING_PLACE_INFO_UNSPECIFIED;
+  }
+
+  public static final class GolfExerciseTypeConfig.GolfShotTrackingPlaceInfo.Companion {
+  }
+
+  public final class HealthEvent {
+    ctor public HealthEvent(androidx.health.services.client.data.HealthEvent.Type type, java.time.Instant eventTime, androidx.health.services.client.data.DataPointContainer metrics);
+    method public java.time.Instant getEventTime();
+    method public androidx.health.services.client.data.DataPointContainer getMetrics();
+    method public androidx.health.services.client.data.HealthEvent.Type getType();
+    property public final java.time.Instant eventTime;
+    property public final androidx.health.services.client.data.DataPointContainer metrics;
+    property public final androidx.health.services.client.data.HealthEvent.Type type;
+  }
+
+  public static final class HealthEvent.Type {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HealthEvent.Type.Companion Companion;
+    field public static final androidx.health.services.client.data.HealthEvent.Type FALL_DETECTED;
+    field public static final androidx.health.services.client.data.HealthEvent.Type UNKNOWN;
+  }
+
+  public static final class HealthEvent.Type.Companion {
+  }
+
+  public final class HeartRateAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public HeartRateAccuracy(androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus);
+    method public androidx.health.services.client.data.HeartRateAccuracy.SensorStatus getSensorStatus();
+    property public final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus sensorStatus;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus {
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_HIGH;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_LOW;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus ACCURACY_MEDIUM;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus.Companion Companion;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus NO_CONTACT;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNKNOWN;
+    field public static final androidx.health.services.client.data.HeartRateAccuracy.SensorStatus UNRELIABLE;
+  }
+
+  public static final class HeartRateAccuracy.SensorStatus.Companion {
+  }
+
+  public final class IntervalDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public IntervalDataPoint(androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType, T value, java.time.Duration startDurationFromBoot, java.time.Duration endDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> getDataType();
+    method public java.time.Duration getEndDurationFromBoot();
+    method public java.time.Instant getEndInstant(java.time.Instant bootInstant);
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getStartDurationFromBoot();
+    method public java.time.Instant getStartInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,? extends androidx.health.services.client.data.IntervalDataPoint<T>> dataType;
+    property public final java.time.Duration endDurationFromBoot;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration startDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class LocationAccuracy extends androidx.health.services.client.data.DataPointAccuracy {
+    ctor public LocationAccuracy(@FloatRange(from=0.0) double horizontalPositionErrorMeters, optional @FloatRange(from=0.0) double verticalPositionErrorMeters);
+    method public double getHorizontalPositionErrorMeters();
+    method public double getVerticalPositionErrorMeters();
+    property public final double horizontalPositionErrorMeters;
+    property public final double verticalPositionErrorMeters;
+    field public static final androidx.health.services.client.data.LocationAccuracy.Companion Companion;
+  }
+
+  public static final class LocationAccuracy.Companion {
+  }
+
+  public final class LocationAvailability implements androidx.health.services.client.data.Availability {
+    method public static androidx.health.services.client.data.LocationAvailability? fromId(int id);
+    method public int getId();
+    method public String getName();
+    property public int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_TETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRED_UNTETHERED;
+    field public static final androidx.health.services.client.data.LocationAvailability ACQUIRING;
+    field public static final androidx.health.services.client.data.LocationAvailability.Companion Companion;
+    field public static final androidx.health.services.client.data.LocationAvailability NO_GNSS;
+    field public static final androidx.health.services.client.data.LocationAvailability UNAVAILABLE;
+    field public static final androidx.health.services.client.data.LocationAvailability UNKNOWN;
+  }
+
+  public static final class LocationAvailability.Companion {
+    method public androidx.health.services.client.data.LocationAvailability? fromId(int id);
+  }
+
+  public final class LocationData {
+    ctor public LocationData(@FloatRange(from=-90.0, to=90.0) double latitude, @FloatRange(from=-180.0, to=180.0) double longitude, optional double altitude, optional double bearing);
+    method public double getAltitude();
+    method public double getBearing();
+    method public double getLatitude();
+    method public double getLongitude();
+    property public final double altitude;
+    property public final double bearing;
+    property public final double latitude;
+    property public final double longitude;
+    field public static final double ALTITUDE_UNAVAILABLE = (0.0/0.0);
+    field public static final double BEARING_UNAVAILABLE = (0.0/0.0);
+  }
+
+  public final class MeasureCapabilities {
+    ctor public MeasureCapabilities(java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getSupportedDataTypesMeasure();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> supportedDataTypesMeasure;
+  }
+
+  public final class MilestoneMarkerSummary {
+    ctor public MilestoneMarkerSummary(java.time.Instant startTime, java.time.Instant endTime, java.time.Duration activeDuration, androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal, androidx.health.services.client.data.DataPointContainer summaryMetrics);
+    method public androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> getAchievedGoal();
+    method public java.time.Duration getActiveDuration();
+    method public java.time.Instant getEndTime();
+    method public java.time.Instant getStartTime();
+    method public androidx.health.services.client.data.DataPointContainer getSummaryMetrics();
+    property public final androidx.health.services.client.data.ExerciseGoal<? extends java.lang.Number> achievedGoal;
+    property public final java.time.Duration activeDuration;
+    property public final java.time.Instant endTime;
+    property public final java.time.Instant startTime;
+    property public final androidx.health.services.client.data.DataPointContainer summaryMetrics;
+  }
+
+  public final class PassiveGoal {
+    ctor public PassiveGoal(androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition);
+    method public androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> getDataTypeCondition();
+    property public final androidx.health.services.client.data.DataTypeCondition<? extends java.lang.Number,? extends androidx.health.services.client.data.DeltaDataType<? extends java.lang.Number,?>> dataTypeCondition;
+  }
+
+  public final class PassiveListenerConfig {
+    ctor public PassiveListenerConfig(java.util.Set<? extends androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes, boolean shouldUserActivityInfoBeRequested, java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public static androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+    method public java.util.Set<androidx.health.services.client.data.PassiveGoal> getDailyGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> getDataTypes();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getHealthEventTypes();
+    method public boolean getShouldUserActivityInfoBeRequested();
+    property public final java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<? extends java.lang.Object,? extends androidx.health.services.client.data.DataPoint<?>>> dataTypes;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes;
+    property public final boolean shouldUserActivityInfoBeRequested;
+    field public static final androidx.health.services.client.data.PassiveListenerConfig.Companion Companion;
+  }
+
+  public static final class PassiveListenerConfig.Builder {
+    ctor public PassiveListenerConfig.Builder();
+    method public androidx.health.services.client.data.PassiveListenerConfig build();
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDailyGoals(java.util.Set<androidx.health.services.client.data.PassiveGoal> dailyGoals);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setDataTypes(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> dataTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setHealthEventTypes(java.util.Set<androidx.health.services.client.data.HealthEvent.Type> healthEventTypes);
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder setShouldUserActivityInfoBeRequested(boolean shouldUserActivityInfoBeRequested);
+  }
+
+  public static final class PassiveListenerConfig.Companion {
+    method public androidx.health.services.client.data.PassiveListenerConfig.Builder builder();
+  }
+
+  public final class PassiveMonitoringCapabilities {
+    ctor public PassiveMonitoringCapabilities(java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring, java.util.Set<? extends androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals, java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes, java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates);
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveGoals();
+    method public java.util.Set<androidx.health.services.client.data.DataType<?,?>> getSupportedDataTypesPassiveMonitoring();
+    method public java.util.Set<androidx.health.services.client.data.HealthEvent.Type> getSupportedHealthEventTypes();
+    method public java.util.Set<androidx.health.services.client.data.UserActivityState> getSupportedUserActivityStates();
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveGoals;
+    property public final java.util.Set<androidx.health.services.client.data.DataType<?,?>> supportedDataTypesPassiveMonitoring;
+    property public final java.util.Set<androidx.health.services.client.data.HealthEvent.Type> supportedHealthEventTypes;
+    property public final java.util.Set<androidx.health.services.client.data.UserActivityState> supportedUserActivityStates;
+  }
+
+  public final class PassiveMonitoringUpdate {
+    ctor public PassiveMonitoringUpdate(androidx.health.services.client.data.DataPointContainer dataPoints, java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates);
+    method public androidx.health.services.client.data.DataPointContainer getDataPoints();
+    method public java.util.List<androidx.health.services.client.data.UserActivityInfo> getUserActivityInfoUpdates();
+    property public final androidx.health.services.client.data.DataPointContainer dataPoints;
+    property public final java.util.List<androidx.health.services.client.data.UserActivityInfo> userActivityInfoUpdates;
+  }
+
+  public final class SampleDataPoint<T> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public SampleDataPoint(androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType, T value, java.time.Duration timeDurationFromBoot, optional android.os.Bundle metadata, optional androidx.health.services.client.data.DataPointAccuracy? accuracy);
+    method public androidx.health.services.client.data.DataPointAccuracy? getAccuracy();
+    method public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> getDataType();
+    method public android.os.Bundle getMetadata();
+    method public java.time.Duration getTimeDurationFromBoot();
+    method public java.time.Instant getTimeInstant(java.time.Instant bootInstant);
+    method public T getValue();
+    property public final androidx.health.services.client.data.DataPointAccuracy? accuracy;
+    property public androidx.health.services.client.data.DataType<T,androidx.health.services.client.data.SampleDataPoint<T>> dataType;
+    property public final android.os.Bundle metadata;
+    property public final java.time.Duration timeDurationFromBoot;
+    property public final T value;
+  }
+
+  public final class StatisticalDataPoint<T extends java.lang.Number> extends androidx.health.services.client.data.DataPoint<T> {
+    ctor public StatisticalDataPoint(androidx.health.services.client.data.AggregateDataType<T,androidx.health.services.client.data.StatisticalDataPoint<T>> dataType, T min, T max, T average, java.time.Instant start, java.time.Instant end);
+    method public T getAverage();
+    method public java.time.Instant getEnd();
+    method public T getMax();
+    method public T getMin();
+    method public java.time.Instant getStart();
+    property public final T average;
+    property public final java.time.Instant end;
+    property public final T max;
+    property public final T min;
+    property public final java.time.Instant start;
+    field public static final androidx.health.services.client.data.StatisticalDataPoint.Companion Companion;
+  }
+
+  public static final class StatisticalDataPoint.Companion {
+  }
+
+  public final class UserActivityInfo {
+    ctor public UserActivityInfo(androidx.health.services.client.data.UserActivityState userActivityState, androidx.health.services.client.data.ExerciseInfo? exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public static androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.ExerciseInfo? getExerciseInfo();
+    method public java.time.Instant getStateChangeTime();
+    method public androidx.health.services.client.data.UserActivityState getUserActivityState();
+    property public final androidx.health.services.client.data.ExerciseInfo? exerciseInfo;
+    property public final java.time.Instant stateChangeTime;
+    property public final androidx.health.services.client.data.UserActivityState userActivityState;
+    field public static final androidx.health.services.client.data.UserActivityInfo.Companion Companion;
+  }
+
+  public static final class UserActivityInfo.Companion {
+    method public androidx.health.services.client.data.UserActivityInfo createActiveExerciseState(androidx.health.services.client.data.ExerciseInfo exerciseInfo, java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createAsleepState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createPassiveActivityState(java.time.Instant stateChangeTime);
+    method public androidx.health.services.client.data.UserActivityInfo createUnknownTypeState(java.time.Instant stateChangeTime);
+  }
+
+  public final class UserActivityState {
+    ctor public UserActivityState(int id, String name);
+    method public int getId();
+    method public String getName();
+    property public final int id;
+    property public final String name;
+    field public static final androidx.health.services.client.data.UserActivityState.Companion Companion;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_ASLEEP;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_EXERCISE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_PASSIVE;
+    field public static final androidx.health.services.client.data.UserActivityState USER_ACTIVITY_UNKNOWN;
+  }
+
+  public static final class UserActivityState.Companion {
+  }
+
+  public final class WarmUpConfig {
+    ctor public WarmUpConfig(androidx.health.services.client.data.ExerciseType exerciseType, java.util.Set<? extends androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes);
+    method public java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> getDataTypes();
+    method public androidx.health.services.client.data.ExerciseType getExerciseType();
+    property public final java.util.Set<androidx.health.services.client.data.DeltaDataType<?,?>> dataTypes;
+    property public final androidx.health.services.client.data.ExerciseType exerciseType;
+  }
+
+}
+
diff --git a/health/health-services-client/api/restricted_current.ignore b/health/health-services-client/api/restricted_current.ignore
deleted file mode 100644
index 091f290..0000000
--- a/health/health-services-client/api/restricted_current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AddedAbstractMethod: androidx.health.services.client.ExerciseClient#overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode>):
-    Added method androidx.health.services.client.ExerciseClient.overrideBatchingModesForActiveExerciseAsync(java.util.Set<androidx.health.services.client.data.BatchingMode>)
diff --git a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/DexInspectorTask.kt b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/DexInspectorTask.kt
index 6f7bb9b..7d95e6b 100644
--- a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/DexInspectorTask.kt
+++ b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/DexInspectorTask.kt
@@ -75,8 +75,11 @@
         val output = outputFile.get().asFile
         output.parentFile.mkdirs()
         val errorStream = ByteArrayOutputStream()
-        val executionResult = execOperations.exec {
-            it.executable = d8Executable.get().asFile.absolutePath
+        val executionResult = execOperations.javaexec {
+            it.classpath(File(File(d8Executable.get().asFile.parentFile, "lib"), "d8.jar"))
+            it.mainClass.set("com.android.tools.r8.D8")
+            it.allJvmArgs.add("-Xmx2G")
+
             val filesToDex = jars.map { file -> file.absolutePath }
 
             // All runtime dependencies of the inspector are already jarjar-ed and packed in
diff --git a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
index 63e8206..8a3832e 100644
--- a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
+++ b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/InspectionPlugin.kt
@@ -25,6 +25,7 @@
 import org.gradle.api.Plugin
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.type.ArtifactTypeDefinition
 import org.gradle.api.attributes.Attribute
 import org.gradle.api.tasks.StopExecutionException
 import org.gradle.kotlin.dsl.apply
@@ -58,6 +59,15 @@
             it.setupNonDexedInspectorAttribute()
         }
 
+        project.configurations.create(EXPORT_INSPECTOR_DEPENDENCIES) {
+            // to allow including these dependencies in an SBOM
+            it.description = "Re-publishes dependencies of the inspector"
+            it.isCanBeConsumed = true
+            it.isCanBeResolved = false
+            it.extendsFrom(project.configurations.getByName("implementation"))
+            it.setupReleaseAttribute()
+        }
+
         project.pluginManager.withPlugin("com.android.library") {
             foundLibraryPlugin = true
             val libExtension = project.extensions.getByType(LibraryExtension::class.java)
@@ -165,7 +175,7 @@
 fun packageInspector(libraryProject: Project, inspectorProjectPath: String) {
     val inspectorProject = libraryProject.rootProject.findProject(inspectorProjectPath)
     if (inspectorProject == null) {
-        check(libraryProject.findProperty("androidx.studio.type") == "playground") {
+        check(libraryProject.property("androidx.studio.type") == "playground") {
             "Cannot find $inspectorProjectPath. This is optional only for playground builds."
         }
         // skip setting up inspector project
@@ -190,6 +200,18 @@
             }
         }
     }
+
+    libraryProject.configurations.create(IMPORT_INSPECTOR_DEPENDENCIES) {
+        it.setupReleaseAttribute()
+    }
+    libraryProject.dependencies.add(IMPORT_INSPECTOR_DEPENDENCIES,
+        libraryProject.dependencies.project(
+            mapOf(
+                "path" to inspectorProjectPath,
+                "configuration" to EXPORT_INSPECTOR_DEPENDENCIES
+            )
+        )
+    )
 }
 
 fun Project.createConsumeInspectionConfiguration(): Configuration =
@@ -214,6 +236,25 @@
     }
 }
 
+private fun Configuration.setupReleaseAttribute() {
+    attributes {
+        it.attribute(
+            Attribute.of(
+                "com.android.build.api.attributes.BuildTypeAttr",
+                String::class.java
+            ),
+            "release"
+        )
+        it.attribute(
+            Attribute.of(
+                "artifactType",
+                String::class.java
+            ),
+            ArtifactTypeDefinition.JAR_TYPE
+        )
+    }
+}
+
 @ExperimentalStdlibApi
 private fun generateProguardDetectionFile(libraryProject: Project) {
     val libExtension = libraryProject.extensions.getByType(LibraryExtension::class.java)
@@ -223,6 +264,8 @@
 }
 
 const val EXTENSION_NAME = "inspection"
+const val EXPORT_INSPECTOR_DEPENDENCIES = "exportInspectorImplementation"
+const val IMPORT_INSPECTOR_DEPENDENCIES = "importInspectorImplementation"
 
 open class InspectionExtension(@Suppress("UNUSED_PARAMETER") project: Project) {
     /**
diff --git a/libraryversions.toml b/libraryversions.toml
index 23b7477..0a39064 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -9,7 +9,7 @@
 ARCH_CORE = "2.3.0-alpha01"
 ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
 AUTOFILL = "1.3.0-alpha01"
-BENCHMARK = "1.2.0-alpha13"
+BENCHMARK = "1.2.0-alpha14"
 BIOMETRIC = "1.2.0-alpha06"
 BLUETOOTH = "1.0.0-alpha01"
 BROWSER = "1.6.0-alpha01"
@@ -19,16 +19,17 @@
 CARDVIEW = "1.1.0-alpha01"
 CAR_APP = "1.4.0-alpha01"
 COLLECTION = "1.3.0-alpha05"
-COMPOSE = "1.5.0-alpha02"
-COMPOSE_COMPILER = "1.4.4"
-COMPOSE_MATERIAL3 = "1.1.0-beta02"
+COMPOSE = "1.5.0-alpha03"
+COMPOSE_COMPILER = "1.4.6"
+COMPOSE_MATERIAL3 = "1.1.0-rc01"
+COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha01"
 COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03"
 CONSTRAINTLAYOUT = "2.2.0-alpha10"
 CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha10"
 CONSTRAINTLAYOUT_CORE = "1.1.0-alpha10"
 CONTENTPAGER = "1.1.0-alpha01"
 COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.11.0-alpha02"
+CORE = "1.11.0-alpha03"
 CORE_ANIMATION = "1.0.0-beta02"
 CORE_ANIMATION_TESTING = "1.0.0-beta01"
 CORE_APPDIGEST = "1.0.0-alpha01"
@@ -39,38 +40,38 @@
 CORE_REMOTEVIEWS = "1.0.0-beta04"
 CORE_ROLE = "1.2.0-alpha01"
 CORE_SPLASHSCREEN = "1.1.0-alpha01"
-CORE_UWB = "1.0.0-alpha05"
-CREDENTIALS = "1.0.0-alpha06"
+CORE_UWB = "1.0.0-alpha06"
+CREDENTIALS = "1.0.0-alpha07"
 CURSORADAPTER = "1.1.0-alpha01"
 CUSTOMVIEW = "1.2.0-alpha03"
 CUSTOMVIEW_POOLINGCONTAINER = "1.1.0-alpha01"
-DATASTORE = "1.1.0-alpha04"
+DATASTORE = "1.1.0-alpha05"
 DOCUMENTFILE = "1.1.0-alpha02"
 DRAGANDDROP = "1.1.0-alpha01"
 DRAWERLAYOUT = "1.3.0-alpha01"
 DYNAMICANIMATION = "1.1.0-alpha04"
 DYNAMICANIMATION_KTX = "1.0.0-alpha04"
 EMOJI = "1.2.0-alpha03"
-EMOJI2 = "1.4.0-beta01"
+EMOJI2 = "1.4.0-beta02"
 ENTERPRISE = "1.1.0-rc01"
 EXIFINTERFACE = "1.4.0-alpha01"
-FRAGMENT = "1.6.0-alpha09"
+FRAGMENT = "1.6.0-beta01"
 FUTURES = "1.2.0-alpha01"
 GLANCE = "1.0.0-alpha06"
 GLANCE_TEMPLATE = "1.0.0-alpha01"
 GRAPHICS_CORE = "1.0.0-alpha04"
 GRAPHICS_FILTERS = "1.0.0-alpha01"
-GRAPHICS_SHAPES = "1.0.0-alpha01"
+GRAPHICS_SHAPES = "1.0.0-alpha02"
 GRIDLAYOUT = "1.1.0-alpha02"
 HEALTH_CONNECT = "1.0.0-alpha11"
-HEALTH_SERVICES_CLIENT = "1.0.0-beta03"
+HEALTH_SERVICES_CLIENT = "1.0.0-beta04"
 HEIFWRITER = "1.1.0-alpha02"
 HILT = "1.1.0-alpha02"
 HILT_NAVIGATION_COMPOSE = "1.1.0-alpha02"
 INPUT_MOTIONPREDICTION = "1.0.0-beta02"
 INSPECTION = "1.0.0"
 INTERPOLATOR = "1.1.0-alpha01"
-JAVASCRIPTENGINE = "1.0.0-alpha05"
+JAVASCRIPTENGINE = "1.0.0-alpha06"
 LEANBACK = "1.2.0-alpha03"
 LEANBACK_GRID = "1.0.0-alpha02"
 LEANBACK_PAGING = "1.1.0-alpha10"
@@ -83,9 +84,9 @@
 LOADER = "1.2.0-alpha01"
 MEDIA = "1.7.0-alpha02"
 MEDIA2 = "1.3.0-alpha01"
-MEDIAROUTER = "1.4.0-rc01"
-METRICS = "1.0.0-alpha04"
-NAVIGATION = "2.6.0-alpha09"
+MEDIAROUTER = "1.5.0-alpha01"
+METRICS = "1.0.0-alpha05"
+NAVIGATION = "2.6.0-beta01"
 PAGING = "3.2.0-alpha05"
 PAGING_COMPOSE = "1.0.0-alpha19"
 PALETTE = "1.1.0-alpha01"
@@ -93,8 +94,8 @@
 PREFERENCE = "1.3.0-alpha01"
 PRINT = "1.1.0-beta01"
 PRIVACYSANDBOX_ADS = "1.0.0-beta03"
-PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha01"
-PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha03"
+PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha02"
+PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha04"
 PRIVACYSANDBOX_TOOLS = "1.0.0-alpha04"
 PRIVACYSANDBOX_UI = "1.0.0-alpha02"
 PROFILEINSTALLER = "1.4.0-alpha01"
@@ -105,7 +106,7 @@
 RESOURCEINSPECTION = "1.1.0-alpha01"
 ROOM = "2.6.0-alpha02"
 SAVEDSTATE = "1.3.0-alpha01"
-SECURITY = "1.1.0-alpha05"
+SECURITY = "1.1.0-alpha06"
 SECURITY_APP_AUTHENTICATOR = "1.0.0-alpha03"
 SECURITY_APP_AUTHENTICATOR_TESTING = "1.0.0-alpha02"
 SECURITY_BIOMETRIC = "1.0.0-alpha01"
@@ -125,8 +126,8 @@
 TESTSCREENSHOT = "1.0.0-alpha01"
 TEST_UIAUTOMATOR = "2.3.0-alpha03"
 TEXT = "1.0.0-alpha01"
-TRACING = "1.2.0-beta03"
-TRACING_PERFETTO = "1.0.0-alpha14"
+TRACING = "1.2.0-beta04"
+TRACING_PERFETTO = "1.0.0-alpha15"
 TRANSITION = "1.5.0-alpha01"
 TV = "1.0.0-alpha06"
 TVPROVIDER = "1.1.0-alpha02"
@@ -137,20 +138,20 @@
 VIEWPAGER = "1.1.0-alpha02"
 VIEWPAGER2 = "1.2.0-alpha01"
 WEAR = "1.3.0-alpha05"
-WEAR_COMPOSE = "1.2.0-alpha08"
-WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha02"
+WEAR_COMPOSE = "1.2.0-alpha09"
+WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha03"
 WEAR_INPUT = "1.2.0-alpha03"
 WEAR_INPUT_TESTING = "1.2.0-alpha03"
 WEAR_ONGOING = "1.1.0-alpha01"
 WEAR_PHONE_INTERACTIONS = "1.1.0-alpha04"
-WEAR_PROTOLAYOUT = "1.0.0-alpha07"
+WEAR_PROTOLAYOUT = "1.0.0-alpha08"
 WEAR_REMOTE_INTERACTIONS = "1.1.0-alpha01"
-WEAR_TILES = "1.2.0-alpha03"
-WEAR_WATCHFACE = "1.2.0-alpha07"
-WEBKIT = "1.7.0-beta01"
-WINDOW = "1.1.0-beta02"
+WEAR_TILES = "1.2.0-alpha04"
+WEAR_WATCHFACE = "1.2.0-alpha08"
+WEBKIT = "1.7.0-beta02"
+WINDOW = "1.1.0-beta03"
 WINDOW_EXTENSIONS = "1.1.0-beta02"
-WINDOW_EXTENSIONS_CORE = "1.0.0-beta02"
+WINDOW_EXTENSIONS_CORE = "1.0.0-beta03"
 WINDOW_SIDECAR = "1.0.0-rc01"
 WORK = "2.9.0-alpha01"
 
@@ -180,6 +181,7 @@
 COMPOSE_FOUNDATION = { group = "androidx.compose.foundation", atomicGroupVersion = "versions.COMPOSE" }
 COMPOSE_MATERIAL = { group = "androidx.compose.material", atomicGroupVersion = "versions.COMPOSE" }
 COMPOSE_MATERIAL3 = { group = "androidx.compose.material3", atomicGroupVersion = "versions.COMPOSE_MATERIAL3" }
+COMPOSE_MATERIAL3_ADAPTIVE = { group = "androidx.compose.material3.material3-adaptive", atomicGroupVersion = "versions.COMPOSE_MATERIAL3_ADAPTIVE", overrideInclude = [ ":material3:material3-adpative" ] }
 COMPOSE_RUNTIME = { group = "androidx.compose.runtime", atomicGroupVersion = "versions.COMPOSE" }
 COMPOSE_UI = { group = "androidx.compose.ui", atomicGroupVersion = "versions.COMPOSE" }
 CONCURRENT = { group = "androidx.concurrent", atomicGroupVersion = "versions.FUTURES" }
diff --git a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
index 84100e2..d23d266 100644
--- a/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
+++ b/lifecycle/integration-tests/incrementality/src/test/kotlin/androidx/lifecycle/IncrementalAnnotationProcessingTest.kt
@@ -18,9 +18,7 @@
 
 import androidx.testutils.gradle.ProjectSetupRule
 import com.google.common.truth.Truth.assertThat
-import org.gradle.tooling.GradleConnector
-import org.gradle.tooling.ProjectConnection
-import org.junit.After
+import org.gradle.testkit.runner.GradleRunner
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -58,7 +56,6 @@
     private lateinit var barObserverClass: File
     private lateinit var genFooAdapterClass: File
     private lateinit var genBarAdapterClass: File
-    private lateinit var projectConnection: ProjectConnection
 
     @Before
     fun setup() {
@@ -103,17 +100,18 @@
         setupSettingsGradle()
         setupAndroidManifest()
         addSource()
+    }
 
-        projectConnection = GradleConnector.newConnector()
-            .forProjectDirectory(projectRoot).connect()
+    fun gradleRunner(): GradleRunner {
+        return GradleRunner.create()
+            .withProjectDir(projectRoot)
     }
 
     @Test
     fun checkModifySource() {
-        projectConnection
-            .newBuild()
-            .forTasks("clean", "compileDebugJavaWithJavac")
-            .run()
+        gradleRunner()
+            .withArguments("clean", "compileDebugJavaWithJavac")
+            .build()
 
         val fooAdapterFirstBuild = Files.getLastModifiedTime(genFooAdapter.toPath()).toMillis()
         val barAdapterFirstBuild = Files.getLastModifiedTime(genBarAdapter.toPath()).toMillis()
@@ -130,10 +128,9 @@
 
         searchAndReplace(fooObserver.toPath(), "FooObserver_Log", "Modified_FooObserver_Log")
 
-        projectConnection
-            .newBuild()
-            .forTasks("compileDebugJavaWithJavac")
-            .run()
+        gradleRunner()
+            .withArguments("compileDebugJavaWithJavac")
+            .build()
 
         val fooAdapterSecondBuild = Files.getLastModifiedTime(genFooAdapter.toPath()).toMillis()
         val barAdapterSecondBuild = Files.getLastModifiedTime(genBarAdapter.toPath()).toMillis()
@@ -164,10 +161,9 @@
 
     @Test
     fun checkDeleteOneSource() {
-        projectConnection
-            .newBuild()
-            .forTasks("clean", "compileDebugJavaWithJavac")
-            .run()
+        gradleRunner()
+            .withArguments("clean", "compileDebugJavaWithJavac")
+            .build()
 
         val barAdapterFirstBuild = Files.getLastModifiedTime(genBarAdapter.toPath()).toMillis()
         val barProguardFirstBuild = Files.getLastModifiedTime(genBarProguard.toPath()).toMillis()
@@ -181,10 +177,9 @@
 
         fooObserver.delete()
 
-        projectConnection
-            .newBuild()
-            .forTasks("compileDebugJavaWithJavac")
-            .run()
+        gradleRunner()
+            .withArguments("compileDebugJavaWithJavac")
+            .build()
 
         val barAdapterSecondBuild = Files.getLastModifiedTime(genBarAdapter.toPath()).toMillis()
         val barProguardSecondBuild = Files.getLastModifiedTime(genBarProguard.toPath()).toMillis()
@@ -204,11 +199,6 @@
         assertThat(barAdapterClassFirstBuild).isEqualTo(barAdapterClassSecondBuild)
     }
 
-    @After
-    fun closeProjectConnection() {
-        projectConnection.close()
-    }
-
     private fun setupProjectBuildGradle() {
         val repositoriesBlock = buildString {
             appendLine("repositories {")
diff --git a/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/SynchronousActivityLifecycleTest.java b/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/SynchronousActivityLifecycleTest.java
index 245ff06..b805615 100644
--- a/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/SynchronousActivityLifecycleTest.java
+++ b/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/SynchronousActivityLifecycleTest.java
@@ -16,6 +16,8 @@
 
 package androidx.lifecycle;
 
+import static android.os.Build.VERSION.SDK_INT;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -37,6 +39,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.rule.UiThreadTestRule;
 
+import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,6 +58,12 @@
     @Rule
     public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
 
+    @Before
+    public void setup() {
+        // b/276959207
+        Assume.assumeTrue(!Build.MODEL.contains("x86") || SDK_INT != 21);
+    }
+
     @Test
     public void testOnCreateCall() throws Throwable {
         testSynchronousCall(Event.ON_CREATE,
@@ -152,7 +162,7 @@
 
     private static void performStop(Activity activity) {
         try {
-            if (Build.VERSION.SDK_INT >= 24) {
+            if (SDK_INT >= 24) {
                 Method m = Activity.class.getDeclaredMethod("performStop", boolean.class);
                 m.setAccessible(true);
                 m.invoke(activity, false);
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/current.ignore b/lifecycle/lifecycle-viewmodel-compose/api/current.ignore
deleted file mode 100644
index 0a5b8ff..0000000
--- a/lifecycle/lifecycle-viewmodel-compose/api/current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.lifecycle.viewmodel.compose.SavedStateHandleSaverKt:
-    Removed class androidx.lifecycle.viewmodel.compose.SavedStateHandleSaverKt
diff --git a/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.ignore b/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.ignore
deleted file mode 100644
index 0a5b8ff..0000000
--- a/lifecycle/lifecycle-viewmodel-compose/api/restricted_current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-RemovedClass: androidx.lifecycle.viewmodel.compose.SavedStateHandleSaverKt:
-    Removed class androidx.lifecycle.viewmodel.compose.SavedStateHandleSaverKt
diff --git a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerTest.java b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerTest.java
index 8cdfda3..db3719c 100644
--- a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerTest.java
+++ b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerTest.java
@@ -39,7 +39,6 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
-import androidx.core.os.BuildCompat;
 import androidx.core.util.Pair;
 import androidx.media.AudioAttributesCompat;
 import androidx.media2.common.MediaItem;
@@ -155,7 +154,7 @@
             // TODO(b/220842943): Re-enable for T and beyond once the version of media2-session
             // used in version-compat-tests/previous/client/build.gradle is one that includes
             // https://r.android.com/1950077.
-            if (!BuildCompat.isAtLeastT()) {
+            if (Build.VERSION.SDK_INT < 33) {
                 fail("custom parcelables shouldn't be allowed for connectionHints");
             }
         } catch (IllegalArgumentException e) {
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTest.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTest.java
index 3622671..d67e84a 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTest.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionTest.java
@@ -29,7 +29,6 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
-import androidx.core.os.BuildCompat;
 import androidx.media2.common.MediaItem;
 import androidx.media2.common.MediaMetadata;
 import androidx.media2.common.SessionPlayer;
@@ -130,7 +129,7 @@
             // TODO(b/220842943): Re-enable for T and beyond once the version of media2-session
             // used in version-compat-tests/previous/service/build.gradle is one that includes
             // https://r.android.com/1950077.
-            if (!BuildCompat.isAtLeastT()) {
+            if (Build.VERSION.SDK_INT < 33) {
                 fail("custom parcelables shouldn't be allowed for extras");
             }
         } catch (IllegalArgumentException e) {
diff --git a/media2/media2-widget/src/main/res/values-or/strings.xml b/media2/media2-widget/src/main/res/values-or/strings.xml
index 79b2be3..d527d032 100644
--- a/media2/media2-widget/src/main/res/values-or/strings.xml
+++ b/media2/media2-widget/src/main/res/values-or/strings.xml
@@ -30,7 +30,7 @@
     <string name="mcv2_music_title_unknown_text" msgid="6037645626002038645">"ଗୀତର ଟାଇଟେଲ୍ ଅଜଣା ଅଟେ"</string>
     <string name="mcv2_music_artist_unknown_text" msgid="5393558204040775454">"କଳାକାର ଅଜଣା ଅଟନ୍ତି"</string>
     <string name="mcv2_playback_error_text" msgid="6061787693725630293">"ଆପଣ ଅନୁରୋଧ କରିଥିବା ଆଇଟମ୍ ଚଲାଯାଇପାରିଲା ନାହିଁ"</string>
-    <string name="mcv2_error_dialog_button" msgid="5940167897992933850">"ଠିକ୍ ଅଛି"</string>
+    <string name="mcv2_error_dialog_button" msgid="5940167897992933850">"ଠିକ ଅଛି"</string>
     <string name="mcv2_back_button_desc" msgid="1540894858499118373">"ପଛକୁ ଫେରନ୍ତୁ"</string>
     <string name="mcv2_overflow_left_button_desc" msgid="2749567167276435888">"ପୂର୍ବବର୍ତ୍ତୀ ବଟନ୍ ତାଲିକାକୁ ଫେରନ୍ତୁ"</string>
     <string name="mcv2_overflow_right_button_desc" msgid="7388732945289831383">"ଅଧିକ ବଟନ୍ ଦେଖନ୍ତୁ"</string>
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
index eb44a5e..6601791 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
@@ -63,7 +64,7 @@
 
     private Context mContext;
     private MediaRouter mRouter;
-    private MediaRouter.Callback mPlaceholderCallback = new MediaRouter.Callback() { };
+    private MediaRouter.Callback mPlaceholderCallback = new MediaRouter.Callback() {};
     StubMediaRouteProviderService mService;
     StubMediaRouteProviderService.StubMediaRouteProvider mProvider;
     MediaRouteProviderService.MediaRouteProviderServiceImplApi30 mServiceImpl;
@@ -117,14 +118,22 @@
 
     @After
     public void tearDown() {
-        getInstrumentation().runOnMainSync(() -> {
-            mRouter.removeCallback(mPlaceholderCallback);
-            for (MediaRouter.Callback callback : mCallbacks) {
-                mRouter.removeCallback(callback);
-            }
-            mCallbacks.clear();
-            MediaRouterTestHelper.resetMediaRouter();
-        });
+        getInstrumentation()
+                .runOnMainSync(
+                        () -> {
+                            for (RoutingSessionInfo sessionInfo :
+                                    mMr2ProviderServiceAdapter.getAllSessionInfo()) {
+                                mMr2ProviderServiceAdapter.onReleaseSession(
+                                        MediaRoute2ProviderService.REQUEST_ID_NONE,
+                                        sessionInfo.getId());
+                            }
+                            mRouter.removeCallback(mPlaceholderCallback);
+                            for (MediaRouter.Callback callback : mCallbacks) {
+                                mRouter.removeCallback(callback);
+                            }
+                            mCallbacks.clear();
+                            MediaRouterTestHelper.resetMediaRouter();
+                        });
         MediaRouter2TestActivity.finishActivity();
     }
 
@@ -191,6 +200,28 @@
 
     @SmallTest
     @Test
+    public void setRouteVolume_onStaticNonGroupRoute() {
+        // We run session creation on the main thread to ensure the route creation from the setup
+        // method happens before the session creation. Otherwise, this call may call into an
+        // inconsistent adapter state.
+        getInstrumentation()
+                .runOnMainSync(
+                        () ->
+                                mMr2ProviderServiceAdapter.onCreateSession(
+                                        MediaRoute2ProviderService.REQUEST_ID_NONE,
+                                        mContext.getPackageName(),
+                                        StubMediaRouteProviderService.ROUTE_ID1,
+                                        /* sessionHints= */ null));
+        StubMediaRouteProviderService.StubMediaRouteProvider.StubRouteController createdController =
+                mProvider.mControllers.get(StubMediaRouteProviderService.ROUTE_ID1);
+        assertNotNull(createdController); // Avoids nullability warning.
+        assertNull(createdController.mLastSetVolume);
+        mMr2ProviderServiceAdapter.setRouteVolume(StubMediaRouteProviderService.ROUTE_ID1, 100);
+        assertEquals(100, (int) createdController.mLastSetVolume);
+    }
+
+    @SmallTest
+    @Test
     public void onBinderDied_releaseRoutingSessions() throws Exception {
         String descriptorId = StubMediaRouteProviderService.ROUTE_ID1;
 
@@ -208,8 +239,9 @@
 
         try {
             List<Messenger> messengers =
-                    mServiceImpl.mClients.stream().map(client -> client.mMessenger)
-                    .collect(Collectors.toList());
+                    mServiceImpl.mClients.stream()
+                            .map(client -> client.mMessenger)
+                            .collect(Collectors.toList());
             getInstrumentation().runOnMainSync(() ->
                     messengers.forEach(mServiceImpl::onBinderDied));
             // It should have no session info.
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
index a0f60b4..97a2e83 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
@@ -21,6 +21,7 @@
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.collection.ArrayMap;
 
 import java.util.ArrayList;
@@ -82,6 +83,7 @@
 
     class StubMediaRouteProvider extends MediaRouteProvider {
         Map<String, MediaRouteDescriptor> mRoutes = new ArrayMap<>();
+        Map<String, StubRouteController> mControllers = new ArrayMap<>();
         boolean mSupportsDynamicGroup = false;
 
         StubMediaRouteProvider(@NonNull Context context) {
@@ -90,7 +92,9 @@
 
         @Override
         public RouteController onCreateRouteController(@NonNull String routeId) {
-            return new StubRouteController(routeId);
+            StubRouteController newController = new StubRouteController(routeId);
+            mControllers.put(routeId, newController);
+            return newController;
         }
 
         public void initializeRoutes() {
@@ -114,6 +118,8 @@
         //TODO: Implement DynamicGroupRouteController
         class StubRouteController extends RouteController {
             final String mRouteId;
+            @Nullable Integer mLastSetVolume;
+
             StubRouteController(String routeId) {
                 mRouteId = routeId;
             }
@@ -133,6 +139,11 @@
                         .build());
                 publishRoutes();
             }
+
+            @Override
+            public void onSetVolume(int volume) {
+                mLastSetVolume = volume;
+            }
         }
     }
 }
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
index d5381f5..53c71e5 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
@@ -177,13 +177,20 @@
         RoutingSessionInfo sessionInfo = builder.build();
         sessionRecord.setSessionInfo(sessionInfo);
 
-        // Create member route controllers if it's a static group. Member route controllers
-        // for a dynamic group will be created after the group route is created.
-        // (DynamicGroupRouteController#notifyDynamicRoutesChanged is called)
-        if ((sessionFlags & (SessionRecord.SESSION_FLAG_GROUP | SessionRecord.SESSION_FLAG_DYNAMIC))
-                == SessionRecord.SESSION_FLAG_GROUP) {
-            sessionRecord.updateMemberRouteControllers(routeId, /*oldSession=*/null,
-                    sessionInfo);
+        if ((sessionFlags & SessionRecord.SESSION_FLAG_DYNAMIC) == 0) {
+            if ((sessionFlags & SessionRecord.SESSION_FLAG_GROUP) != 0) {
+                // Create member route controllers if it's a static group. Member route controllers
+                // for a dynamic group will be created after the group route is created.
+                // (DynamicGroupRouteController#notifyDynamicRoutesChanged is called).
+                sessionRecord.updateMemberRouteControllers(
+                        routeId, /* oldSession= */ null, sessionInfo);
+            } else {
+                // The session has a non-group static route controller, whose proxy route
+                // controller has already been created. We just need to map the route id to said
+                // controller, for the controller to be found by its corresponding route id via
+                // findControllerByRouteId (needed, for example, for route volume adjustment).
+                sessionRecord.setStaticMemberRouteId(routeId);
+            }
         }
 
         mServiceImpl.setDynamicRoutesChangedListener(controller);
@@ -665,6 +672,19 @@
             mClientRecord = new WeakReference<>(clientRecord);
         }
 
+        /**
+         * Maps the provided {@code routeId} to the top level route controller of this session.
+         *
+         * <p>This method can be used for mapping a route id to a non-group static route controller.
+         * The session record takes care of the creation of the member route controllers, but not of
+         * the top level route controller, which is provided via the constructor. In the case of
+         * non-group static routes, the top level route controller is the single route controller,
+         * and has already been created, so we only need to map the corresponding route id to it.
+         */
+        public void setStaticMemberRouteId(String routeId) {
+            mRouteIdToControllerMap.put(routeId, mController);
+        }
+
         public int getFlags() {
             return mFlags;
         }
diff --git a/navigation/navigation-common-ktx/api/2.6.0-beta01.txt b/navigation/navigation-common-ktx/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-common-ktx/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-common-ktx/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-common-ktx/api/res-2.6.0-beta01.txt b/navigation/navigation-common-ktx/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-common-ktx/api/restricted_2.6.0-beta01.txt b/navigation/navigation-common-ktx/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-common-ktx/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-common/api/2.6.0-beta01.txt b/navigation/navigation-common/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..de2b551
--- /dev/null
+++ b/navigation/navigation-common/api/2.6.0-beta01.txt
@@ -0,0 +1,530 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+    ctor public ActionOnlyNavDirections(int actionId);
+    method public int component1();
+    method public androidx.navigation.ActionOnlyNavDirections copy(int actionId);
+    method public int getActionId();
+    method public android.os.Bundle getArguments();
+    property public int actionId;
+    property public android.os.Bundle arguments;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+    ctor public AnimBuilder();
+    method public int getEnter();
+    method public int getExit();
+    method public int getPopEnter();
+    method public int getPopExit();
+    method public void setEnter(int);
+    method public void setExit(int);
+    method public void setPopEnter(int);
+    method public void setPopExit(int);
+    property public final int enter;
+    property public final int exit;
+    property public final int popEnter;
+    property public final int popExit;
+  }
+
+  public interface FloatingWindow {
+  }
+
+  public final class NamedNavArgument {
+    method public operator String component1();
+    method public operator androidx.navigation.NavArgument component2();
+    method public androidx.navigation.NavArgument getArgument();
+    method public String getName();
+    property public final androidx.navigation.NavArgument argument;
+    property public final String name;
+  }
+
+  public final class NamedNavArgumentKt {
+    method public static androidx.navigation.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavAction {
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions, optional android.os.Bundle? defaultArguments);
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions);
+    ctor public NavAction(@IdRes int destinationId);
+    method public android.os.Bundle? getDefaultArguments();
+    method public int getDestinationId();
+    method public androidx.navigation.NavOptions? getNavOptions();
+    method public void setDefaultArguments(android.os.Bundle?);
+    method public void setNavOptions(androidx.navigation.NavOptions?);
+    property public final android.os.Bundle? defaultArguments;
+    property public final int destinationId;
+    property public final androidx.navigation.NavOptions? navOptions;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+    ctor public NavActionBuilder();
+    method public java.util.Map<java.lang.String,java.lang.Object> getDefaultArguments();
+    method public int getDestinationId();
+    method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+    method public void setDestinationId(int);
+    property public final java.util.Map<java.lang.String,java.lang.Object> defaultArguments;
+    property public final int destinationId;
+  }
+
+  public interface NavArgs {
+  }
+
+  public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+    ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+    method public Args getValue();
+    method public boolean isInitialized();
+    property public Args value;
+  }
+
+  public final class NavArgument {
+    method public Object? getDefaultValue();
+    method public androidx.navigation.NavType<java.lang.Object> getType();
+    method public boolean isDefaultValuePresent();
+    method public boolean isNullable();
+    property public final Object? defaultValue;
+    property public final boolean isDefaultValuePresent;
+    property public final boolean isNullable;
+    property public final androidx.navigation.NavType<java.lang.Object> type;
+  }
+
+  public static final class NavArgument.Builder {
+    ctor public NavArgument.Builder();
+    method public androidx.navigation.NavArgument build();
+    method public androidx.navigation.NavArgument.Builder setDefaultValue(Object? defaultValue);
+    method public androidx.navigation.NavArgument.Builder setIsNullable(boolean isNullable);
+    method public <T> androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<T> type);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+    ctor public NavArgumentBuilder();
+    method public androidx.navigation.NavArgument build();
+    method public Object? getDefaultValue();
+    method public boolean getNullable();
+    method public androidx.navigation.NavType<?> getType();
+    method public void setDefaultValue(Object?);
+    method public void setNullable(boolean);
+    method public void setType(androidx.navigation.NavType<?>);
+    property public final Object? defaultValue;
+    property public final boolean nullable;
+    property public final androidx.navigation.NavType<?> type;
+  }
+
+  public final class NavBackStackEntry implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    method public android.os.Bundle? getArguments();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public androidx.navigation.NavDestination getDestination();
+    method public String getId();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public androidx.lifecycle.SavedStateHandle getSavedStateHandle();
+    method public androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    property public final android.os.Bundle? arguments;
+    property public androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+    property public androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+    property public final androidx.navigation.NavDestination destination;
+    property public final String id;
+    property public androidx.lifecycle.Lifecycle lifecycle;
+    property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
+    property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+    property public androidx.lifecycle.ViewModelStore viewModelStore;
+  }
+
+  public final class NavDeepLink {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public static final class NavDeepLink.Builder {
+    method public androidx.navigation.NavDeepLink build();
+    method public static androidx.navigation.NavDeepLink.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLink.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLink.Builder fromUriPattern(String uriPattern);
+    method public androidx.navigation.NavDeepLink.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLink.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLink.Builder setUriPattern(String uriPattern);
+  }
+
+  @kotlin.DslMarker public @interface NavDeepLinkDsl {
+  }
+
+  @androidx.navigation.NavDeepLinkDsl public final class NavDeepLinkDslBuilder {
+    ctor public NavDeepLinkDslBuilder();
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    method public void setAction(String?);
+    method public void setMimeType(String?);
+    method public void setUriPattern(String?);
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public final class NavDeepLinkDslBuilderKt {
+    method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
+  }
+
+  public class NavDeepLinkRequest {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public android.net.Uri? getUri();
+    property public String? action;
+    property public String? mimeType;
+    property public android.net.Uri? uri;
+  }
+
+  public static final class NavDeepLinkRequest.Builder {
+    method public androidx.navigation.NavDeepLinkRequest build();
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setUri(android.net.Uri uri);
+    field public static final androidx.navigation.NavDeepLinkRequest.Builder.Companion Companion;
+  }
+
+  public static final class NavDeepLinkRequest.Builder.Companion {
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+  }
+
+  public class NavDestination {
+    ctor public NavDestination(String navigatorName);
+    ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final void addArgument(String argumentName, androidx.navigation.NavArgument argument);
+    method public final void addDeepLink(String uriPattern);
+    method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
+    method public final String? fillInLabel(android.content.Context context, android.os.Bundle? bundle);
+    method public final androidx.navigation.NavAction? getAction(@IdRes int id);
+    method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method @IdRes public final int getId();
+    method public final CharSequence? getLabel();
+    method public final String getNavigatorName();
+    method public final androidx.navigation.NavGraph? getParent();
+    method public final String? getRoute();
+    method public boolean hasDeepLink(android.net.Uri deepLink);
+    method public boolean hasDeepLink(androidx.navigation.NavDeepLinkRequest deepLinkRequest);
+    method @CallSuper public void onInflate(android.content.Context context, android.util.AttributeSet attrs);
+    method protected static final <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    method public final void putAction(@IdRes int actionId, @IdRes int destId);
+    method public final void putAction(@IdRes int actionId, androidx.navigation.NavAction action);
+    method public final void removeAction(@IdRes int actionId);
+    method public final void removeArgument(String argumentName);
+    method public final void setId(@IdRes int);
+    method public final void setLabel(CharSequence?);
+    method public final void setRoute(String?);
+    property public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> arguments;
+    property @IdRes public final int id;
+    property public final CharSequence? label;
+    property public final String navigatorName;
+    property public final androidx.navigation.NavGraph? parent;
+    property public final String? route;
+    field public static final androidx.navigation.NavDestination.Companion Companion;
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface NavDestination.ClassType {
+    method public abstract kotlin.reflect.KClass<?> value();
+    property public abstract kotlin.reflect.KClass<?> value;
+  }
+
+  public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+    ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+    ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
+    method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+    method public D build();
+    method public final void deepLink(String uriPattern);
+    method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
+    method public final int getId();
+    method public final CharSequence? getLabel();
+    method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+    method public final String? getRoute();
+    method public final void setLabel(CharSequence?);
+    property public final int id;
+    property public final CharSequence? label;
+    property protected final androidx.navigation.Navigator<? extends D> navigator;
+    property public final String? route;
+  }
+
+  @kotlin.DslMarker public @interface NavDestinationDsl {
+  }
+
+  public interface NavDirections {
+    method @IdRes public int getActionId();
+    method public android.os.Bundle getArguments();
+    property @IdRes public abstract int actionId;
+    property public abstract android.os.Bundle arguments;
+  }
+
+  public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph> navGraphNavigator);
+    method public final void addAll(androidx.navigation.NavGraph other);
+    method public final void addDestination(androidx.navigation.NavDestination node);
+    method public final void addDestinations(java.util.Collection<? extends androidx.navigation.NavDestination> nodes);
+    method public final void addDestinations(androidx.navigation.NavDestination... nodes);
+    method public final void clear();
+    method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
+    method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+    method @Deprecated @IdRes public final int getStartDestination();
+    method @IdRes public final int getStartDestinationId();
+    method public final String? getStartDestinationRoute();
+    method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+    method public final void remove(androidx.navigation.NavDestination node);
+    method public final void setStartDestination(int startDestId);
+    method public final void setStartDestination(String startDestRoute);
+    property @IdRes public final int startDestinationId;
+    property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+    ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
+    method public final void addDestination(androidx.navigation.NavDestination destination);
+    method public androidx.navigation.NavGraph build();
+    method public final <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+    method public final androidx.navigation.NavigatorProvider getProvider();
+    method public final operator void unaryPlus(androidx.navigation.NavDestination);
+    property public final androidx.navigation.NavigatorProvider provider;
+  }
+
+  public final class NavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavGraphKt {
+    method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+    method public static operator boolean contains(androidx.navigation.NavGraph, String route);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, String route);
+    method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+    ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph createDestination();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  public final class NavOptions {
+    method @AnimRes @AnimatorRes public int getEnterAnim();
+    method @AnimRes @AnimatorRes public int getExitAnim();
+    method @AnimRes @AnimatorRes public int getPopEnterAnim();
+    method @AnimRes @AnimatorRes public int getPopExitAnim();
+    method @Deprecated @IdRes public int getPopUpTo();
+    method @IdRes public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean isPopUpToInclusive();
+    method public boolean shouldLaunchSingleTop();
+    method public boolean shouldPopUpToSaveState();
+    method public boolean shouldRestoreState();
+    property @AnimRes @AnimatorRes public final int enterAnim;
+    property @AnimRes @AnimatorRes public final int exitAnim;
+    property @AnimRes @AnimatorRes public final int popEnterAnim;
+    property @AnimRes @AnimatorRes public final int popExitAnim;
+    property @IdRes public final int popUpToId;
+    property public final String? popUpToRoute;
+  }
+
+  public static final class NavOptions.Builder {
+    ctor public NavOptions.Builder();
+    method public androidx.navigation.NavOptions build();
+    method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int enterAnim);
+    method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int exitAnim);
+    method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean singleTop);
+    method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int popEnterAnim);
+    method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int popExitAnim);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setRestoreState(boolean restoreState);
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+    ctor public NavOptionsBuilder();
+    method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+    method public boolean getLaunchSingleTop();
+    method @Deprecated public int getPopUpTo();
+    method public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean getRestoreState();
+    method public void popUpTo(@IdRes int id, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void popUpTo(String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void setLaunchSingleTop(boolean);
+    method @Deprecated public void setPopUpTo(int);
+    method public void setRestoreState(boolean);
+    property public final boolean launchSingleTop;
+    property @Deprecated public final int popUpTo;
+    property public final int popUpToId;
+    property public final String? popUpToRoute;
+    property public final boolean restoreState;
+  }
+
+  public final class NavOptionsBuilderKt {
+    method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+  }
+
+  @kotlin.DslMarker public @interface NavOptionsDsl {
+  }
+
+  public abstract class NavType<T> {
+    ctor public NavType(boolean isNullableAllowed);
+    method public static androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+    method public abstract operator T? get(android.os.Bundle bundle, String key);
+    method public String getName();
+    method public boolean isNullableAllowed();
+    method public abstract T! parseValue(String value);
+    method public T! parseValue(String value, T? previousValue);
+    method public abstract void put(android.os.Bundle bundle, String key, T? value);
+    method public String serializeAsValue(T? value);
+    property public boolean isNullableAllowed;
+    property public String name;
+    field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+    field public static final androidx.navigation.NavType.Companion Companion;
+    field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+    field public static final androidx.navigation.NavType<int[]> IntArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+    field public static final androidx.navigation.NavType<long[]> LongArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+    field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+    field public static final androidx.navigation.NavType<java.lang.String> StringType;
+  }
+
+  public static final class NavType.Companion {
+    method public androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+  }
+
+  public static final class NavType.EnumType<D extends java.lang.Enum<?>> extends androidx.navigation.NavType.SerializableType<D> {
+    ctor public NavType.EnumType(Class<D> type);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.ParcelableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+    ctor public NavType.ParcelableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D! parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D? value);
+    property public String name;
+  }
+
+  public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.SerializableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+    ctor public NavType.SerializableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D value);
+    property public String name;
+  }
+
+  public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+    ctor public Navigator();
+    method public abstract D createDestination();
+    method protected final androidx.navigation.NavigatorState getState();
+    method public final boolean isAttached();
+    method public void navigate(java.util.List<androidx.navigation.NavBackStackEntry> entries, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method public androidx.navigation.NavDestination? navigate(D destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @CallSuper public void onAttach(androidx.navigation.NavigatorState state);
+    method public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void onRestoreState(android.os.Bundle savedState);
+    method public android.os.Bundle? onSaveState();
+    method public void popBackStack(androidx.navigation.NavBackStackEntry popUpTo, boolean savedState);
+    method public boolean popBackStack();
+    property public final boolean isAttached;
+    property protected final androidx.navigation.NavigatorState state;
+  }
+
+  public static interface Navigator.Extras {
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface Navigator.Name {
+    method public abstract String value();
+    property public abstract String value;
+  }
+
+  public class NavigatorProvider {
+    ctor public NavigatorProvider();
+    method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T> navigatorClass);
+    method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String name);
+  }
+
+  public final class NavigatorProviderKt {
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+    method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+  }
+
+  public abstract class NavigatorState {
+    ctor public NavigatorState();
+    method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+    method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    method @CallSuper public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method @CallSuper public void onLaunchSingleTopWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method @CallSuper public void prepareForTransition(androidx.navigation.NavBackStackEntry entry);
+    method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+    ctor public PopUpToBuilder();
+    method public boolean getInclusive();
+    method public boolean getSaveState();
+    method public void setInclusive(boolean);
+    method public void setSaveState(boolean);
+    property public final boolean inclusive;
+    property public final boolean saveState;
+  }
+
+}
+
diff --git a/navigation/navigation-common/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-common/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..de2b551
--- /dev/null
+++ b/navigation/navigation-common/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,530 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+    ctor public ActionOnlyNavDirections(int actionId);
+    method public int component1();
+    method public androidx.navigation.ActionOnlyNavDirections copy(int actionId);
+    method public int getActionId();
+    method public android.os.Bundle getArguments();
+    property public int actionId;
+    property public android.os.Bundle arguments;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+    ctor public AnimBuilder();
+    method public int getEnter();
+    method public int getExit();
+    method public int getPopEnter();
+    method public int getPopExit();
+    method public void setEnter(int);
+    method public void setExit(int);
+    method public void setPopEnter(int);
+    method public void setPopExit(int);
+    property public final int enter;
+    property public final int exit;
+    property public final int popEnter;
+    property public final int popExit;
+  }
+
+  public interface FloatingWindow {
+  }
+
+  public final class NamedNavArgument {
+    method public operator String component1();
+    method public operator androidx.navigation.NavArgument component2();
+    method public androidx.navigation.NavArgument getArgument();
+    method public String getName();
+    property public final androidx.navigation.NavArgument argument;
+    property public final String name;
+  }
+
+  public final class NamedNavArgumentKt {
+    method public static androidx.navigation.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavAction {
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions, optional android.os.Bundle? defaultArguments);
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions);
+    ctor public NavAction(@IdRes int destinationId);
+    method public android.os.Bundle? getDefaultArguments();
+    method public int getDestinationId();
+    method public androidx.navigation.NavOptions? getNavOptions();
+    method public void setDefaultArguments(android.os.Bundle?);
+    method public void setNavOptions(androidx.navigation.NavOptions?);
+    property public final android.os.Bundle? defaultArguments;
+    property public final int destinationId;
+    property public final androidx.navigation.NavOptions? navOptions;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+    ctor public NavActionBuilder();
+    method public java.util.Map<java.lang.String,java.lang.Object> getDefaultArguments();
+    method public int getDestinationId();
+    method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+    method public void setDestinationId(int);
+    property public final java.util.Map<java.lang.String,java.lang.Object> defaultArguments;
+    property public final int destinationId;
+  }
+
+  public interface NavArgs {
+  }
+
+  public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+    ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+    method public Args getValue();
+    method public boolean isInitialized();
+    property public Args value;
+  }
+
+  public final class NavArgument {
+    method public Object? getDefaultValue();
+    method public androidx.navigation.NavType<java.lang.Object> getType();
+    method public boolean isDefaultValuePresent();
+    method public boolean isNullable();
+    property public final Object? defaultValue;
+    property public final boolean isDefaultValuePresent;
+    property public final boolean isNullable;
+    property public final androidx.navigation.NavType<java.lang.Object> type;
+  }
+
+  public static final class NavArgument.Builder {
+    ctor public NavArgument.Builder();
+    method public androidx.navigation.NavArgument build();
+    method public androidx.navigation.NavArgument.Builder setDefaultValue(Object? defaultValue);
+    method public androidx.navigation.NavArgument.Builder setIsNullable(boolean isNullable);
+    method public <T> androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<T> type);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+    ctor public NavArgumentBuilder();
+    method public androidx.navigation.NavArgument build();
+    method public Object? getDefaultValue();
+    method public boolean getNullable();
+    method public androidx.navigation.NavType<?> getType();
+    method public void setDefaultValue(Object?);
+    method public void setNullable(boolean);
+    method public void setType(androidx.navigation.NavType<?>);
+    property public final Object? defaultValue;
+    property public final boolean nullable;
+    property public final androidx.navigation.NavType<?> type;
+  }
+
+  public final class NavBackStackEntry implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    method public android.os.Bundle? getArguments();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public androidx.navigation.NavDestination getDestination();
+    method public String getId();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public androidx.lifecycle.SavedStateHandle getSavedStateHandle();
+    method public androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    property public final android.os.Bundle? arguments;
+    property public androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+    property public androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+    property public final androidx.navigation.NavDestination destination;
+    property public final String id;
+    property public androidx.lifecycle.Lifecycle lifecycle;
+    property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
+    property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+    property public androidx.lifecycle.ViewModelStore viewModelStore;
+  }
+
+  public final class NavDeepLink {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public static final class NavDeepLink.Builder {
+    method public androidx.navigation.NavDeepLink build();
+    method public static androidx.navigation.NavDeepLink.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLink.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLink.Builder fromUriPattern(String uriPattern);
+    method public androidx.navigation.NavDeepLink.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLink.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLink.Builder setUriPattern(String uriPattern);
+  }
+
+  @kotlin.DslMarker public @interface NavDeepLinkDsl {
+  }
+
+  @androidx.navigation.NavDeepLinkDsl public final class NavDeepLinkDslBuilder {
+    ctor public NavDeepLinkDslBuilder();
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    method public void setAction(String?);
+    method public void setMimeType(String?);
+    method public void setUriPattern(String?);
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public final class NavDeepLinkDslBuilderKt {
+    method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
+  }
+
+  public class NavDeepLinkRequest {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public android.net.Uri? getUri();
+    property public String? action;
+    property public String? mimeType;
+    property public android.net.Uri? uri;
+  }
+
+  public static final class NavDeepLinkRequest.Builder {
+    method public androidx.navigation.NavDeepLinkRequest build();
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setUri(android.net.Uri uri);
+    field public static final androidx.navigation.NavDeepLinkRequest.Builder.Companion Companion;
+  }
+
+  public static final class NavDeepLinkRequest.Builder.Companion {
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+  }
+
+  public class NavDestination {
+    ctor public NavDestination(String navigatorName);
+    ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final void addArgument(String argumentName, androidx.navigation.NavArgument argument);
+    method public final void addDeepLink(String uriPattern);
+    method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
+    method public final String? fillInLabel(android.content.Context context, android.os.Bundle? bundle);
+    method public final androidx.navigation.NavAction? getAction(@IdRes int id);
+    method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method @IdRes public final int getId();
+    method public final CharSequence? getLabel();
+    method public final String getNavigatorName();
+    method public final androidx.navigation.NavGraph? getParent();
+    method public final String? getRoute();
+    method public boolean hasDeepLink(android.net.Uri deepLink);
+    method public boolean hasDeepLink(androidx.navigation.NavDeepLinkRequest deepLinkRequest);
+    method @CallSuper public void onInflate(android.content.Context context, android.util.AttributeSet attrs);
+    method protected static final <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    method public final void putAction(@IdRes int actionId, @IdRes int destId);
+    method public final void putAction(@IdRes int actionId, androidx.navigation.NavAction action);
+    method public final void removeAction(@IdRes int actionId);
+    method public final void removeArgument(String argumentName);
+    method public final void setId(@IdRes int);
+    method public final void setLabel(CharSequence?);
+    method public final void setRoute(String?);
+    property public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> arguments;
+    property @IdRes public final int id;
+    property public final CharSequence? label;
+    property public final String navigatorName;
+    property public final androidx.navigation.NavGraph? parent;
+    property public final String? route;
+    field public static final androidx.navigation.NavDestination.Companion Companion;
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface NavDestination.ClassType {
+    method public abstract kotlin.reflect.KClass<?> value();
+    property public abstract kotlin.reflect.KClass<?> value;
+  }
+
+  public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+    ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+    ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
+    method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+    method public D build();
+    method public final void deepLink(String uriPattern);
+    method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
+    method public final int getId();
+    method public final CharSequence? getLabel();
+    method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+    method public final String? getRoute();
+    method public final void setLabel(CharSequence?);
+    property public final int id;
+    property public final CharSequence? label;
+    property protected final androidx.navigation.Navigator<? extends D> navigator;
+    property public final String? route;
+  }
+
+  @kotlin.DslMarker public @interface NavDestinationDsl {
+  }
+
+  public interface NavDirections {
+    method @IdRes public int getActionId();
+    method public android.os.Bundle getArguments();
+    property @IdRes public abstract int actionId;
+    property public abstract android.os.Bundle arguments;
+  }
+
+  public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph> navGraphNavigator);
+    method public final void addAll(androidx.navigation.NavGraph other);
+    method public final void addDestination(androidx.navigation.NavDestination node);
+    method public final void addDestinations(java.util.Collection<? extends androidx.navigation.NavDestination> nodes);
+    method public final void addDestinations(androidx.navigation.NavDestination... nodes);
+    method public final void clear();
+    method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
+    method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+    method @Deprecated @IdRes public final int getStartDestination();
+    method @IdRes public final int getStartDestinationId();
+    method public final String? getStartDestinationRoute();
+    method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+    method public final void remove(androidx.navigation.NavDestination node);
+    method public final void setStartDestination(int startDestId);
+    method public final void setStartDestination(String startDestRoute);
+    property @IdRes public final int startDestinationId;
+    property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+    ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
+    method public final void addDestination(androidx.navigation.NavDestination destination);
+    method public androidx.navigation.NavGraph build();
+    method public final <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+    method public final androidx.navigation.NavigatorProvider getProvider();
+    method public final operator void unaryPlus(androidx.navigation.NavDestination);
+    property public final androidx.navigation.NavigatorProvider provider;
+  }
+
+  public final class NavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavGraphKt {
+    method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+    method public static operator boolean contains(androidx.navigation.NavGraph, String route);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, String route);
+    method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+    ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph createDestination();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  public final class NavOptions {
+    method @AnimRes @AnimatorRes public int getEnterAnim();
+    method @AnimRes @AnimatorRes public int getExitAnim();
+    method @AnimRes @AnimatorRes public int getPopEnterAnim();
+    method @AnimRes @AnimatorRes public int getPopExitAnim();
+    method @Deprecated @IdRes public int getPopUpTo();
+    method @IdRes public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean isPopUpToInclusive();
+    method public boolean shouldLaunchSingleTop();
+    method public boolean shouldPopUpToSaveState();
+    method public boolean shouldRestoreState();
+    property @AnimRes @AnimatorRes public final int enterAnim;
+    property @AnimRes @AnimatorRes public final int exitAnim;
+    property @AnimRes @AnimatorRes public final int popEnterAnim;
+    property @AnimRes @AnimatorRes public final int popExitAnim;
+    property @IdRes public final int popUpToId;
+    property public final String? popUpToRoute;
+  }
+
+  public static final class NavOptions.Builder {
+    ctor public NavOptions.Builder();
+    method public androidx.navigation.NavOptions build();
+    method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int enterAnim);
+    method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int exitAnim);
+    method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean singleTop);
+    method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int popEnterAnim);
+    method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int popExitAnim);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setRestoreState(boolean restoreState);
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+    ctor public NavOptionsBuilder();
+    method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+    method public boolean getLaunchSingleTop();
+    method @Deprecated public int getPopUpTo();
+    method public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean getRestoreState();
+    method public void popUpTo(@IdRes int id, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void popUpTo(String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void setLaunchSingleTop(boolean);
+    method @Deprecated public void setPopUpTo(int);
+    method public void setRestoreState(boolean);
+    property public final boolean launchSingleTop;
+    property @Deprecated public final int popUpTo;
+    property public final int popUpToId;
+    property public final String? popUpToRoute;
+    property public final boolean restoreState;
+  }
+
+  public final class NavOptionsBuilderKt {
+    method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+  }
+
+  @kotlin.DslMarker public @interface NavOptionsDsl {
+  }
+
+  public abstract class NavType<T> {
+    ctor public NavType(boolean isNullableAllowed);
+    method public static androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+    method public abstract operator T? get(android.os.Bundle bundle, String key);
+    method public String getName();
+    method public boolean isNullableAllowed();
+    method public abstract T! parseValue(String value);
+    method public T! parseValue(String value, T? previousValue);
+    method public abstract void put(android.os.Bundle bundle, String key, T? value);
+    method public String serializeAsValue(T? value);
+    property public boolean isNullableAllowed;
+    property public String name;
+    field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+    field public static final androidx.navigation.NavType.Companion Companion;
+    field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+    field public static final androidx.navigation.NavType<int[]> IntArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+    field public static final androidx.navigation.NavType<long[]> LongArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+    field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+    field public static final androidx.navigation.NavType<java.lang.String> StringType;
+  }
+
+  public static final class NavType.Companion {
+    method public androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+  }
+
+  public static final class NavType.EnumType<D extends java.lang.Enum<?>> extends androidx.navigation.NavType.SerializableType<D> {
+    ctor public NavType.EnumType(Class<D> type);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.ParcelableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+    ctor public NavType.ParcelableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D! parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D? value);
+    property public String name;
+  }
+
+  public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.SerializableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+    ctor public NavType.SerializableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D value);
+    property public String name;
+  }
+
+  public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+    ctor public Navigator();
+    method public abstract D createDestination();
+    method protected final androidx.navigation.NavigatorState getState();
+    method public final boolean isAttached();
+    method public void navigate(java.util.List<androidx.navigation.NavBackStackEntry> entries, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method public androidx.navigation.NavDestination? navigate(D destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @CallSuper public void onAttach(androidx.navigation.NavigatorState state);
+    method public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void onRestoreState(android.os.Bundle savedState);
+    method public android.os.Bundle? onSaveState();
+    method public void popBackStack(androidx.navigation.NavBackStackEntry popUpTo, boolean savedState);
+    method public boolean popBackStack();
+    property public final boolean isAttached;
+    property protected final androidx.navigation.NavigatorState state;
+  }
+
+  public static interface Navigator.Extras {
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface Navigator.Name {
+    method public abstract String value();
+    property public abstract String value;
+  }
+
+  public class NavigatorProvider {
+    ctor public NavigatorProvider();
+    method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T> navigatorClass);
+    method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String name);
+  }
+
+  public final class NavigatorProviderKt {
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+    method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+  }
+
+  public abstract class NavigatorState {
+    ctor public NavigatorState();
+    method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+    method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    method @CallSuper public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method @CallSuper public void onLaunchSingleTopWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method @CallSuper public void prepareForTransition(androidx.navigation.NavBackStackEntry entry);
+    method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+    ctor public PopUpToBuilder();
+    method public boolean getInclusive();
+    method public boolean getSaveState();
+    method public void setInclusive(boolean);
+    method public void setSaveState(boolean);
+    property public final boolean inclusive;
+    property public final boolean saveState;
+  }
+
+}
+
diff --git a/navigation/navigation-common/api/res-2.6.0-beta01.txt b/navigation/navigation-common/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-common/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-common/api/restricted_2.6.0-beta01.txt b/navigation/navigation-common/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..de2b551
--- /dev/null
+++ b/navigation/navigation-common/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,530 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActionOnlyNavDirections implements androidx.navigation.NavDirections {
+    ctor public ActionOnlyNavDirections(int actionId);
+    method public int component1();
+    method public androidx.navigation.ActionOnlyNavDirections copy(int actionId);
+    method public int getActionId();
+    method public android.os.Bundle getArguments();
+    property public int actionId;
+    property public android.os.Bundle arguments;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class AnimBuilder {
+    ctor public AnimBuilder();
+    method public int getEnter();
+    method public int getExit();
+    method public int getPopEnter();
+    method public int getPopExit();
+    method public void setEnter(int);
+    method public void setExit(int);
+    method public void setPopEnter(int);
+    method public void setPopExit(int);
+    property public final int enter;
+    property public final int exit;
+    property public final int popEnter;
+    property public final int popExit;
+  }
+
+  public interface FloatingWindow {
+  }
+
+  public final class NamedNavArgument {
+    method public operator String component1();
+    method public operator androidx.navigation.NavArgument component2();
+    method public androidx.navigation.NavArgument getArgument();
+    method public String getName();
+    property public final androidx.navigation.NavArgument argument;
+    property public final String name;
+  }
+
+  public final class NamedNavArgumentKt {
+    method public static androidx.navigation.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavAction {
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions, optional android.os.Bundle? defaultArguments);
+    ctor public NavAction(@IdRes int destinationId, optional androidx.navigation.NavOptions? navOptions);
+    ctor public NavAction(@IdRes int destinationId);
+    method public android.os.Bundle? getDefaultArguments();
+    method public int getDestinationId();
+    method public androidx.navigation.NavOptions? getNavOptions();
+    method public void setDefaultArguments(android.os.Bundle?);
+    method public void setNavOptions(androidx.navigation.NavOptions?);
+    property public final android.os.Bundle? defaultArguments;
+    property public final int destinationId;
+    property public final androidx.navigation.NavOptions? navOptions;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavActionBuilder {
+    ctor public NavActionBuilder();
+    method public java.util.Map<java.lang.String,java.lang.Object> getDefaultArguments();
+    method public int getDestinationId();
+    method public void navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+    method public void setDestinationId(int);
+    property public final java.util.Map<java.lang.String,java.lang.Object> defaultArguments;
+    property public final int destinationId;
+  }
+
+  public interface NavArgs {
+  }
+
+  public final class NavArgsLazy<Args extends androidx.navigation.NavArgs> implements kotlin.Lazy<Args> {
+    ctor public NavArgsLazy(kotlin.reflect.KClass<Args> navArgsClass, kotlin.jvm.functions.Function0<android.os.Bundle> argumentProducer);
+    method public Args getValue();
+    method public boolean isInitialized();
+    property public Args value;
+  }
+
+  public final class NavArgument {
+    method public Object? getDefaultValue();
+    method public androidx.navigation.NavType<java.lang.Object> getType();
+    method public boolean isDefaultValuePresent();
+    method public boolean isNullable();
+    property public final Object? defaultValue;
+    property public final boolean isDefaultValuePresent;
+    property public final boolean isNullable;
+    property public final androidx.navigation.NavType<java.lang.Object> type;
+  }
+
+  public static final class NavArgument.Builder {
+    ctor public NavArgument.Builder();
+    method public androidx.navigation.NavArgument build();
+    method public androidx.navigation.NavArgument.Builder setDefaultValue(Object? defaultValue);
+    method public androidx.navigation.NavArgument.Builder setIsNullable(boolean isNullable);
+    method public <T> androidx.navigation.NavArgument.Builder setType(androidx.navigation.NavType<T> type);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class NavArgumentBuilder {
+    ctor public NavArgumentBuilder();
+    method public androidx.navigation.NavArgument build();
+    method public Object? getDefaultValue();
+    method public boolean getNullable();
+    method public androidx.navigation.NavType<?> getType();
+    method public void setDefaultValue(Object?);
+    method public void setNullable(boolean);
+    method public void setType(androidx.navigation.NavType<?>);
+    property public final Object? defaultValue;
+    property public final boolean nullable;
+    property public final androidx.navigation.NavType<?> type;
+  }
+
+  public final class NavBackStackEntry implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    method public android.os.Bundle? getArguments();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public androidx.navigation.NavDestination getDestination();
+    method public String getId();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public androidx.lifecycle.SavedStateHandle getSavedStateHandle();
+    method public androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    property public final android.os.Bundle? arguments;
+    property public androidx.lifecycle.viewmodel.CreationExtras defaultViewModelCreationExtras;
+    property public androidx.lifecycle.ViewModelProvider.Factory defaultViewModelProviderFactory;
+    property public final androidx.navigation.NavDestination destination;
+    property public final String id;
+    property public androidx.lifecycle.Lifecycle lifecycle;
+    property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
+    property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+    property public androidx.lifecycle.ViewModelStore viewModelStore;
+  }
+
+  public final class NavDeepLink {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public static final class NavDeepLink.Builder {
+    method public androidx.navigation.NavDeepLink build();
+    method public static androidx.navigation.NavDeepLink.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLink.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLink.Builder fromUriPattern(String uriPattern);
+    method public androidx.navigation.NavDeepLink.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLink.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLink.Builder setUriPattern(String uriPattern);
+  }
+
+  @kotlin.DslMarker public @interface NavDeepLinkDsl {
+  }
+
+  @androidx.navigation.NavDeepLinkDsl public final class NavDeepLinkDslBuilder {
+    ctor public NavDeepLinkDslBuilder();
+    method public String? getAction();
+    method public String? getMimeType();
+    method public String? getUriPattern();
+    method public void setAction(String?);
+    method public void setMimeType(String?);
+    method public void setUriPattern(String?);
+    property public final String? action;
+    property public final String? mimeType;
+    property public final String? uriPattern;
+  }
+
+  public final class NavDeepLinkDslBuilderKt {
+    method public static androidx.navigation.NavDeepLink navDeepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> deepLinkBuilder);
+  }
+
+  public class NavDeepLinkRequest {
+    method public String? getAction();
+    method public String? getMimeType();
+    method public android.net.Uri? getUri();
+    property public String? action;
+    property public String? mimeType;
+    property public android.net.Uri? uri;
+  }
+
+  public static final class NavDeepLinkRequest.Builder {
+    method public androidx.navigation.NavDeepLinkRequest build();
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public static androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder setUri(android.net.Uri uri);
+    field public static final androidx.navigation.NavDeepLinkRequest.Builder.Companion Companion;
+  }
+
+  public static final class NavDeepLinkRequest.Builder.Companion {
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromAction(String action);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromMimeType(String mimeType);
+    method public androidx.navigation.NavDeepLinkRequest.Builder fromUri(android.net.Uri uri);
+  }
+
+  public class NavDestination {
+    ctor public NavDestination(String navigatorName);
+    ctor public NavDestination(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final void addArgument(String argumentName, androidx.navigation.NavArgument argument);
+    method public final void addDeepLink(String uriPattern);
+    method public final void addDeepLink(androidx.navigation.NavDeepLink navDeepLink);
+    method public final String? fillInLabel(android.content.Context context, android.os.Bundle? bundle);
+    method public final androidx.navigation.NavAction? getAction(@IdRes int id);
+    method public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> getArguments();
+    method public static final kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method @IdRes public final int getId();
+    method public final CharSequence? getLabel();
+    method public final String getNavigatorName();
+    method public final androidx.navigation.NavGraph? getParent();
+    method public final String? getRoute();
+    method public boolean hasDeepLink(android.net.Uri deepLink);
+    method public boolean hasDeepLink(androidx.navigation.NavDeepLinkRequest deepLinkRequest);
+    method @CallSuper public void onInflate(android.content.Context context, android.util.AttributeSet attrs);
+    method protected static final <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+    method public final void putAction(@IdRes int actionId, @IdRes int destId);
+    method public final void putAction(@IdRes int actionId, androidx.navigation.NavAction action);
+    method public final void removeAction(@IdRes int actionId);
+    method public final void removeArgument(String argumentName);
+    method public final void setId(@IdRes int);
+    method public final void setLabel(CharSequence?);
+    method public final void setRoute(String?);
+    property public final java.util.Map<java.lang.String,androidx.navigation.NavArgument> arguments;
+    property @IdRes public final int id;
+    property public final CharSequence? label;
+    property public final String navigatorName;
+    property public final androidx.navigation.NavGraph? parent;
+    property public final String? route;
+    field public static final androidx.navigation.NavDestination.Companion Companion;
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface NavDestination.ClassType {
+    method public abstract kotlin.reflect.KClass<?> value();
+    property public abstract kotlin.reflect.KClass<?> value;
+  }
+
+  public static final class NavDestination.Companion {
+    method public kotlin.sequences.Sequence<androidx.navigation.NavDestination> getHierarchy(androidx.navigation.NavDestination);
+    method protected <C> Class<? extends C> parseClassFromName(android.content.Context context, String name, Class<? extends C> expectedClassType);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavDestinationBuilder<D extends androidx.navigation.NavDestination> {
+    ctor @Deprecated public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, @IdRes int id);
+    ctor public NavDestinationBuilder(androidx.navigation.Navigator<? extends D> navigator, String? route);
+    method @Deprecated public final void action(int actionId, kotlin.jvm.functions.Function1<? super androidx.navigation.NavActionBuilder,kotlin.Unit> actionBuilder);
+    method public final void argument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> argumentBuilder);
+    method public D build();
+    method public final void deepLink(String uriPattern);
+    method public final void deepLink(kotlin.jvm.functions.Function1<? super androidx.navigation.NavDeepLinkDslBuilder,kotlin.Unit> navDeepLink);
+    method public final int getId();
+    method public final CharSequence? getLabel();
+    method protected final androidx.navigation.Navigator<? extends D> getNavigator();
+    method public final String? getRoute();
+    method public final void setLabel(CharSequence?);
+    property public final int id;
+    property public final CharSequence? label;
+    property protected final androidx.navigation.Navigator<? extends D> navigator;
+    property public final String? route;
+  }
+
+  @kotlin.DslMarker public @interface NavDestinationDsl {
+  }
+
+  public interface NavDirections {
+    method @IdRes public int getActionId();
+    method public android.os.Bundle getArguments();
+    property @IdRes public abstract int actionId;
+    property public abstract android.os.Bundle arguments;
+  }
+
+  public class NavGraph extends androidx.navigation.NavDestination implements java.lang.Iterable<androidx.navigation.NavDestination> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public NavGraph(androidx.navigation.Navigator<? extends androidx.navigation.NavGraph> navGraphNavigator);
+    method public final void addAll(androidx.navigation.NavGraph other);
+    method public final void addDestination(androidx.navigation.NavDestination node);
+    method public final void addDestinations(java.util.Collection<? extends androidx.navigation.NavDestination> nodes);
+    method public final void addDestinations(androidx.navigation.NavDestination... nodes);
+    method public final void clear();
+    method public final androidx.navigation.NavDestination? findNode(@IdRes int resId);
+    method public final androidx.navigation.NavDestination? findNode(String? route);
+    method public static final androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+    method @Deprecated @IdRes public final int getStartDestination();
+    method @IdRes public final int getStartDestinationId();
+    method public final String? getStartDestinationRoute();
+    method public final java.util.Iterator<androidx.navigation.NavDestination> iterator();
+    method public final void remove(androidx.navigation.NavDestination node);
+    method public final void setStartDestination(int startDestId);
+    method public final void setStartDestination(String startDestRoute);
+    property @IdRes public final int startDestinationId;
+    property public final String? startDestinationRoute;
+    field public static final androidx.navigation.NavGraph.Companion Companion;
+  }
+
+  public static final class NavGraph.Companion {
+    method public androidx.navigation.NavDestination findStartDestination(androidx.navigation.NavGraph);
+  }
+
+  @androidx.navigation.NavDestinationDsl public class NavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.NavGraph> {
+    ctor @Deprecated public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public NavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, String? route);
+    method public final void addDestination(androidx.navigation.NavDestination destination);
+    method public androidx.navigation.NavGraph build();
+    method public final <D extends androidx.navigation.NavDestination> void destination(androidx.navigation.NavDestinationBuilder<? extends D> navDestination);
+    method public final androidx.navigation.NavigatorProvider getProvider();
+    method public final operator void unaryPlus(androidx.navigation.NavDestination);
+    property public final androidx.navigation.NavigatorProvider provider;
+  }
+
+  public final class NavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.NavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavGraphKt {
+    method public static operator boolean contains(androidx.navigation.NavGraph, @IdRes int id);
+    method public static operator boolean contains(androidx.navigation.NavGraph, String route);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);
+    method public static inline operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, String route);
+    method public static inline operator void minusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavDestination node);
+    method public static inline operator void plusAssign(androidx.navigation.NavGraph, androidx.navigation.NavGraph other);
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public class NavGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.NavGraph> {
+    ctor public NavGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph createDestination();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  public final class NavOptions {
+    method @AnimRes @AnimatorRes public int getEnterAnim();
+    method @AnimRes @AnimatorRes public int getExitAnim();
+    method @AnimRes @AnimatorRes public int getPopEnterAnim();
+    method @AnimRes @AnimatorRes public int getPopExitAnim();
+    method @Deprecated @IdRes public int getPopUpTo();
+    method @IdRes public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean isPopUpToInclusive();
+    method public boolean shouldLaunchSingleTop();
+    method public boolean shouldPopUpToSaveState();
+    method public boolean shouldRestoreState();
+    property @AnimRes @AnimatorRes public final int enterAnim;
+    property @AnimRes @AnimatorRes public final int exitAnim;
+    property @AnimRes @AnimatorRes public final int popEnterAnim;
+    property @AnimRes @AnimatorRes public final int popExitAnim;
+    property @IdRes public final int popUpToId;
+    property public final String? popUpToRoute;
+  }
+
+  public static final class NavOptions.Builder {
+    ctor public NavOptions.Builder();
+    method public androidx.navigation.NavOptions build();
+    method public androidx.navigation.NavOptions.Builder setEnterAnim(@AnimRes @AnimatorRes int enterAnim);
+    method public androidx.navigation.NavOptions.Builder setExitAnim(@AnimRes @AnimatorRes int exitAnim);
+    method public androidx.navigation.NavOptions.Builder setLaunchSingleTop(boolean singleTop);
+    method public androidx.navigation.NavOptions.Builder setPopEnterAnim(@AnimRes @AnimatorRes int popEnterAnim);
+    method public androidx.navigation.NavOptions.Builder setPopExitAnim(@AnimRes @AnimatorRes int popExitAnim);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(@IdRes int destinationId, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive, optional boolean saveState);
+    method public androidx.navigation.NavOptions.Builder setPopUpTo(String? route, boolean inclusive);
+    method public androidx.navigation.NavOptions.Builder setRestoreState(boolean restoreState);
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class NavOptionsBuilder {
+    ctor public NavOptionsBuilder();
+    method public void anim(kotlin.jvm.functions.Function1<? super androidx.navigation.AnimBuilder,kotlin.Unit> animBuilder);
+    method public boolean getLaunchSingleTop();
+    method @Deprecated public int getPopUpTo();
+    method public int getPopUpToId();
+    method public String? getPopUpToRoute();
+    method public boolean getRestoreState();
+    method public void popUpTo(@IdRes int id, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void popUpTo(String route, optional kotlin.jvm.functions.Function1<? super androidx.navigation.PopUpToBuilder,kotlin.Unit> popUpToBuilder);
+    method public void setLaunchSingleTop(boolean);
+    method @Deprecated public void setPopUpTo(int);
+    method public void setRestoreState(boolean);
+    property public final boolean launchSingleTop;
+    property @Deprecated public final int popUpTo;
+    property public final int popUpToId;
+    property public final String? popUpToRoute;
+    property public final boolean restoreState;
+  }
+
+  public final class NavOptionsBuilderKt {
+    method public static androidx.navigation.NavOptions navOptions(kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> optionsBuilder);
+  }
+
+  @kotlin.DslMarker public @interface NavOptionsDsl {
+  }
+
+  public abstract class NavType<T> {
+    ctor public NavType(boolean isNullableAllowed);
+    method public static androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+    method public abstract operator T? get(android.os.Bundle bundle, String key);
+    method public String getName();
+    method public boolean isNullableAllowed();
+    method public abstract T! parseValue(String value);
+    method public T! parseValue(String value, T? previousValue);
+    method public abstract void put(android.os.Bundle bundle, String key, T? value);
+    method public String serializeAsValue(T? value);
+    property public boolean isNullableAllowed;
+    property public String name;
+    field public static final androidx.navigation.NavType<boolean[]> BoolArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Boolean> BoolType;
+    field public static final androidx.navigation.NavType.Companion Companion;
+    field public static final androidx.navigation.NavType<float[]> FloatArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Float> FloatType;
+    field public static final androidx.navigation.NavType<int[]> IntArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> IntType;
+    field public static final androidx.navigation.NavType<long[]> LongArrayType;
+    field public static final androidx.navigation.NavType<java.lang.Long> LongType;
+    field public static final androidx.navigation.NavType<java.lang.Integer> ReferenceType;
+    field public static final androidx.navigation.NavType<java.lang.String[]> StringArrayType;
+    field public static final androidx.navigation.NavType<java.lang.String> StringType;
+  }
+
+  public static final class NavType.Companion {
+    method public androidx.navigation.NavType<?> fromArgType(String? type, String? packageName);
+  }
+
+  public static final class NavType.EnumType<D extends java.lang.Enum<?>> extends androidx.navigation.NavType.SerializableType<D> {
+    ctor public NavType.EnumType(Class<D> type);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableArrayType<D extends android.os.Parcelable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.ParcelableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static final class NavType.ParcelableType<D> extends androidx.navigation.NavType<D> {
+    ctor public NavType.ParcelableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D! parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D? value);
+    property public String name;
+  }
+
+  public static final class NavType.SerializableArrayType<D extends java.io.Serializable> extends androidx.navigation.NavType<D[]> {
+    ctor public NavType.SerializableArrayType(Class<D> type);
+    method public D![]? get(android.os.Bundle bundle, String key);
+    method public D![] parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D![]? value);
+    property public String name;
+  }
+
+  public static class NavType.SerializableType<D extends java.io.Serializable> extends androidx.navigation.NavType<D> {
+    ctor public NavType.SerializableType(Class<D> type);
+    method public D? get(android.os.Bundle bundle, String key);
+    method public D parseValue(String value);
+    method public void put(android.os.Bundle bundle, String key, D value);
+    property public String name;
+  }
+
+  public abstract class Navigator<D extends androidx.navigation.NavDestination> {
+    ctor public Navigator();
+    method public abstract D createDestination();
+    method protected final androidx.navigation.NavigatorState getState();
+    method public final boolean isAttached();
+    method public void navigate(java.util.List<androidx.navigation.NavBackStackEntry> entries, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method public androidx.navigation.NavDestination? navigate(D destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @CallSuper public void onAttach(androidx.navigation.NavigatorState state);
+    method public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void onRestoreState(android.os.Bundle savedState);
+    method public android.os.Bundle? onSaveState();
+    method public void popBackStack(androidx.navigation.NavBackStackEntry popUpTo, boolean savedState);
+    method public boolean popBackStack();
+    property public final boolean isAttached;
+    property protected final androidx.navigation.NavigatorState state;
+  }
+
+  public static interface Navigator.Extras {
+  }
+
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface Navigator.Name {
+    method public abstract String value();
+    property public abstract String value;
+  }
+
+  public class NavigatorProvider {
+    ctor public NavigatorProvider();
+    method public final androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method @CallSuper public androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? addNavigator(String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public final <T extends androidx.navigation.Navigator<?>> T getNavigator(Class<T> navigatorClass);
+    method @CallSuper public <T extends androidx.navigation.Navigator<?>> T getNavigator(String name);
+  }
+
+  public final class NavigatorProviderKt {
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, String name);
+    method public static inline operator <T extends androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);
+    method public static inline operator void plusAssign(androidx.navigation.NavigatorProvider, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+    method public static inline operator androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>? set(androidx.navigation.NavigatorProvider, String name, androidx.navigation.Navigator<? extends androidx.navigation.NavDestination> navigator);
+  }
+
+  public abstract class NavigatorState {
+    ctor public NavigatorState();
+    method public abstract androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> getTransitionsInProgress();
+    method public void markTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    method @CallSuper public void onLaunchSingleTop(androidx.navigation.NavBackStackEntry backStackEntry);
+    method @CallSuper public void onLaunchSingleTopWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pop(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method public void popWithTransition(androidx.navigation.NavBackStackEntry popUpTo, boolean saveState);
+    method @CallSuper public void prepareForTransition(androidx.navigation.NavBackStackEntry entry);
+    method public void push(androidx.navigation.NavBackStackEntry backStackEntry);
+    method public void pushWithTransition(androidx.navigation.NavBackStackEntry backStackEntry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.Set<androidx.navigation.NavBackStackEntry>> transitionsInProgress;
+  }
+
+  @androidx.navigation.NavOptionsDsl public final class PopUpToBuilder {
+    ctor public PopUpToBuilder();
+    method public boolean getInclusive();
+    method public boolean getSaveState();
+    method public void setInclusive(boolean);
+    method public void setSaveState(boolean);
+    property public final boolean inclusive;
+    property public final boolean saveState;
+  }
+
+}
+
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
index 2803a2e..36301ef 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
@@ -271,6 +271,15 @@
         return result
     }
 
+    override fun toString(): String {
+        val sb = StringBuilder()
+        sb.append(javaClass.simpleName)
+        sb.append("($id)")
+        sb.append(" destination=")
+        sb.append(destination)
+        return sb.toString()
+    }
+
     /**
      * Used to create the {SavedStateViewModel}
      */
diff --git a/navigation/navigation-compose/api/2.6.0-beta01.txt b/navigation/navigation-compose/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..73c5c5d
--- /dev/null
+++ b/navigation/navigation-compose/api/2.6.0-beta01.txt
@@ -0,0 +1,50 @@
+// Signature format: 4.0
+package androidx.navigation.compose {
+
+  @androidx.navigation.Navigator.Name("composable") public final class ComposeNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.ComposeNavigator.Destination> {
+    ctor public ComposeNavigator();
+    method public androidx.navigation.compose.ComposeNavigator.Destination createDestination();
+    method public kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public void onTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class ComposeNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class DialogHostKt {
+    method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
+    ctor public DialogNavigator();
+    method public androidx.navigation.compose.DialogNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class DialogNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class NavBackStackEntryProviderKt {
+    method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class NavGraphBuilderKt {
+    method public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void dialog(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostControllerKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+    method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>... navigators);
+  }
+
+  public final class NavHostKt {
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier);
+  }
+
+}
+
diff --git a/navigation/navigation-compose/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-compose/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..73c5c5d
--- /dev/null
+++ b/navigation/navigation-compose/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,50 @@
+// Signature format: 4.0
+package androidx.navigation.compose {
+
+  @androidx.navigation.Navigator.Name("composable") public final class ComposeNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.ComposeNavigator.Destination> {
+    ctor public ComposeNavigator();
+    method public androidx.navigation.compose.ComposeNavigator.Destination createDestination();
+    method public kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public void onTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class ComposeNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class DialogHostKt {
+    method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
+    ctor public DialogNavigator();
+    method public androidx.navigation.compose.DialogNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class DialogNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class NavBackStackEntryProviderKt {
+    method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class NavGraphBuilderKt {
+    method public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void dialog(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostControllerKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+    method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>... navigators);
+  }
+
+  public final class NavHostKt {
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier);
+  }
+
+}
+
diff --git a/navigation/navigation-compose/api/res-2.6.0-beta01.txt b/navigation/navigation-compose/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-compose/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-compose/api/restricted_2.6.0-beta01.txt b/navigation/navigation-compose/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..73c5c5d
--- /dev/null
+++ b/navigation/navigation-compose/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,50 @@
+// Signature format: 4.0
+package androidx.navigation.compose {
+
+  @androidx.navigation.Navigator.Name("composable") public final class ComposeNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.ComposeNavigator.Destination> {
+    ctor public ComposeNavigator();
+    method public androidx.navigation.compose.ComposeNavigator.Destination createDestination();
+    method public kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getBackStack();
+    method public void onTransitionComplete(androidx.navigation.NavBackStackEntry entry);
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> backStack;
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class ComposeNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class DialogHostKt {
+    method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
+    ctor public DialogNavigator();
+    method public androidx.navigation.compose.DialogNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Composable::class) public static final class DialogNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogNavigator.Destination(androidx.navigation.compose.DialogNavigator navigator, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+  }
+
+  public final class NavBackStackEntryProviderKt {
+    method @androidx.compose.runtime.Composable public static void LocalOwnersProvider(androidx.navigation.NavBackStackEntry, androidx.compose.runtime.saveable.SaveableStateHolder saveableStateHolder, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  public final class NavGraphBuilderKt {
+    method public static void composable(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void dialog(androidx.navigation.NavGraphBuilder, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, optional androidx.compose.ui.window.DialogProperties dialogProperties, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void navigation(androidx.navigation.NavGraphBuilder, String startDestination, String route, optional java.util.List<androidx.navigation.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostControllerKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<androidx.navigation.NavBackStackEntry> currentBackStackEntryAsState(androidx.navigation.NavController);
+    method @androidx.compose.runtime.Composable public static androidx.navigation.NavHostController rememberNavController(androidx.navigation.Navigator<? extends androidx.navigation.NavDestination>... navigators);
+  }
+
+  public final class NavHostKt {
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, String startDestination, optional androidx.compose.ui.Modifier modifier, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method @androidx.compose.runtime.Composable public static void NavHost(androidx.navigation.NavHostController navController, androidx.navigation.NavGraph graph, optional androidx.compose.ui.Modifier modifier);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-fragment/api/2.6.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..fe32d9b
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/2.6.0-beta01.txt
@@ -0,0 +1,69 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures.fragment {
+
+  @androidx.navigation.Navigator.Name("fragment") public final class DynamicFragmentNavigator extends androidx.navigation.fragment.FragmentNavigator {
+    ctor public DynamicFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager manager, int containerId, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicFragmentNavigator.Destination extends androidx.navigation.fragment.FragmentNavigator.Destination {
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+    ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  public final class DynamicFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public class DynamicNavHostFragment extends androidx.navigation.fragment.NavHostFragment {
+    ctor public DynamicNavHostFragment();
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+    method protected com.google.android.play.core.splitinstall.SplitInstallManager createSplitInstallManager();
+    field public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment.Companion Companion;
+  }
+
+  public static final class DynamicNavHostFragment.Companion {
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+  }
+
+}
+
+package androidx.navigation.dynamicfeatures.fragment.ui {
+
+  public abstract class AbstractProgressFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractProgressFragment();
+    ctor public AbstractProgressFragment(int contentLayoutId);
+    method protected abstract void onCancelled();
+    method protected abstract void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onInstalled();
+    method protected abstract void onProgress(@com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus int status, long bytesDownloaded, long bytesTotal);
+  }
+
+  public final class DefaultProgressFragment extends androidx.navigation.dynamicfeatures.fragment.ui.AbstractProgressFragment {
+    ctor public DefaultProgressFragment();
+    method protected void onCancelled();
+    method protected void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onProgress(int status, long bytesDownloaded, long bytesTotal);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..fe32d9b
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,69 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures.fragment {
+
+  @androidx.navigation.Navigator.Name("fragment") public final class DynamicFragmentNavigator extends androidx.navigation.fragment.FragmentNavigator {
+    ctor public DynamicFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager manager, int containerId, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicFragmentNavigator.Destination extends androidx.navigation.fragment.FragmentNavigator.Destination {
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+    ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  public final class DynamicFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public class DynamicNavHostFragment extends androidx.navigation.fragment.NavHostFragment {
+    ctor public DynamicNavHostFragment();
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+    method protected com.google.android.play.core.splitinstall.SplitInstallManager createSplitInstallManager();
+    field public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment.Companion Companion;
+  }
+
+  public static final class DynamicNavHostFragment.Companion {
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+  }
+
+}
+
+package androidx.navigation.dynamicfeatures.fragment.ui {
+
+  public abstract class AbstractProgressFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractProgressFragment();
+    ctor public AbstractProgressFragment(int contentLayoutId);
+    method protected abstract void onCancelled();
+    method protected abstract void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onInstalled();
+    method protected abstract void onProgress(@com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus int status, long bytesDownloaded, long bytesTotal);
+  }
+
+  public final class DefaultProgressFragment extends androidx.navigation.dynamicfeatures.fragment.ui.AbstractProgressFragment {
+    ctor public DefaultProgressFragment();
+    method protected void onCancelled();
+    method protected void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onProgress(int status, long bytesDownloaded, long bytesTotal);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-fragment/api/res-2.6.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-dynamic-features-fragment/api/restricted_2.6.0-beta01.txt b/navigation/navigation-dynamic-features-fragment/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..fe32d9b
--- /dev/null
+++ b/navigation/navigation-dynamic-features-fragment/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,69 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures.fragment {
+
+  @androidx.navigation.Navigator.Name("fragment") public final class DynamicFragmentNavigator extends androidx.navigation.fragment.FragmentNavigator {
+    ctor public DynamicFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager manager, int containerId, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicFragmentNavigator.Destination extends androidx.navigation.fragment.FragmentNavigator.Destination {
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, @IdRes int id, String fragmentClassName);
+    ctor public DynamicFragmentNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator navigator, String route, String fragmentClassName);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigator.Destination build();
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  public final class DynamicFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String fragmentClassName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.fragment.DynamicFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public class DynamicNavHostFragment extends androidx.navigation.fragment.NavHostFragment {
+    ctor public DynamicNavHostFragment();
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+    method protected com.google.android.play.core.splitinstall.SplitInstallManager createSplitInstallManager();
+    field public static final androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment.Companion Companion;
+  }
+
+  public static final class DynamicNavHostFragment.Companion {
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment create(@NavigationRes int graphResId);
+  }
+
+}
+
+package androidx.navigation.dynamicfeatures.fragment.ui {
+
+  public abstract class AbstractProgressFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractProgressFragment();
+    ctor public AbstractProgressFragment(int contentLayoutId);
+    method protected abstract void onCancelled();
+    method protected abstract void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onInstalled();
+    method protected abstract void onProgress(@com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus int status, long bytesDownloaded, long bytesTotal);
+  }
+
+  public final class DefaultProgressFragment extends androidx.navigation.dynamicfeatures.fragment.ui.AbstractProgressFragment {
+    ctor public DefaultProgressFragment();
+    method protected void onCancelled();
+    method protected void onFailed(@com.google.android.play.core.splitinstall.model.SplitInstallErrorCode int errorCode);
+    method protected void onProgress(int status, long bytesDownloaded, long bytesTotal);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/api/2.6.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..e4c37db
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/2.6.0-beta01.txt
@@ -0,0 +1,154 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures {
+
+  @androidx.navigation.Navigator.Name("activity") public final class DynamicActivityNavigator extends androidx.navigation.ActivityNavigator {
+    ctor public DynamicActivityNavigator(android.content.Context context, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicActivityNavigator.Destination extends androidx.navigation.ActivityNavigator.Destination {
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+    ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
+    method public String? getAction();
+    method public String? getActivityClassName();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getModuleName();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClassName(String?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setModuleName(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final String? activityClassName;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? moduleName;
+    property public final String? targetPackage;
+  }
+
+  public final class DynamicActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class DynamicExtras implements androidx.navigation.Navigator.Extras {
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor, optional androidx.navigation.Navigator.Extras? destinationExtras);
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor);
+    ctor public DynamicExtras();
+    method public androidx.navigation.Navigator.Extras? getDestinationExtras();
+    method public androidx.navigation.dynamicfeatures.DynamicInstallMonitor? getInstallMonitor();
+    property public final androidx.navigation.Navigator.Extras? destinationExtras;
+    property public final androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor;
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public final class DynamicGraphNavigator extends androidx.navigation.NavGraphNavigator {
+    ctor public DynamicGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicGraphNavigator.DynamicNavGraph createDestination();
+    method public void installDefaultProgressDestination(kotlin.jvm.functions.Function0<? extends androidx.navigation.NavDestination> progressDestinationSupplier);
+  }
+
+  public static final class DynamicGraphNavigator.DynamicNavGraph extends androidx.navigation.NavGraph {
+    ctor public DynamicGraphNavigator.DynamicNavGraph(androidx.navigation.dynamicfeatures.DynamicGraphNavigator navGraphNavigator, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    property public final String? moduleName;
+    property public final int progressDestination;
+  }
+
+  @androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
+  }
+
+  public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
+    method public String? getGraphPackage();
+    method public String? getGraphResourceName();
+    method public String? getModuleName();
+    method public void setGraphPackage(String?);
+    method public void setGraphResourceName(String?);
+    method public void setModuleName(String?);
+    property public final String? graphPackage;
+    property public final String? graphResourceName;
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+    ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
+    method public String? getGraphPackage();
+    method public void setGraphPackage(String?);
+    property public final String? graphPackage;
+  }
+
+  public final class DynamicIncludeNavGraphBuilderKt {
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public class DynamicInstallManager {
+    ctor public DynamicInstallManager(android.content.Context context, com.google.android.play.core.splitinstall.SplitInstallManager splitInstallManager);
+  }
+
+  public final class DynamicInstallMonitor {
+    ctor public DynamicInstallMonitor();
+    method public void cancelInstall();
+    method public Exception? getException();
+    method public int getSessionId();
+    method public androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> getStatus();
+    method public boolean isInstallRequired();
+    property public final Exception? exception;
+    property public final boolean isInstallRequired;
+    property public final int sessionId;
+    property public final androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> status;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
+    ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public String? getProgressDestinationRoute();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    method public void setProgressDestinationRoute(String?);
+    property public final String? moduleName;
+    property public final int progressDestination;
+    property public final String? progressDestinationRoute;
+  }
+
+  public final class DynamicNavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..e4c37db
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,154 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures {
+
+  @androidx.navigation.Navigator.Name("activity") public final class DynamicActivityNavigator extends androidx.navigation.ActivityNavigator {
+    ctor public DynamicActivityNavigator(android.content.Context context, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicActivityNavigator.Destination extends androidx.navigation.ActivityNavigator.Destination {
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+    ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
+    method public String? getAction();
+    method public String? getActivityClassName();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getModuleName();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClassName(String?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setModuleName(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final String? activityClassName;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? moduleName;
+    property public final String? targetPackage;
+  }
+
+  public final class DynamicActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class DynamicExtras implements androidx.navigation.Navigator.Extras {
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor, optional androidx.navigation.Navigator.Extras? destinationExtras);
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor);
+    ctor public DynamicExtras();
+    method public androidx.navigation.Navigator.Extras? getDestinationExtras();
+    method public androidx.navigation.dynamicfeatures.DynamicInstallMonitor? getInstallMonitor();
+    property public final androidx.navigation.Navigator.Extras? destinationExtras;
+    property public final androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor;
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public final class DynamicGraphNavigator extends androidx.navigation.NavGraphNavigator {
+    ctor public DynamicGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicGraphNavigator.DynamicNavGraph createDestination();
+    method public void installDefaultProgressDestination(kotlin.jvm.functions.Function0<? extends androidx.navigation.NavDestination> progressDestinationSupplier);
+  }
+
+  public static final class DynamicGraphNavigator.DynamicNavGraph extends androidx.navigation.NavGraph {
+    ctor public DynamicGraphNavigator.DynamicNavGraph(androidx.navigation.dynamicfeatures.DynamicGraphNavigator navGraphNavigator, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    property public final String? moduleName;
+    property public final int progressDestination;
+  }
+
+  @androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
+  }
+
+  public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
+    method public String? getGraphPackage();
+    method public String? getGraphResourceName();
+    method public String? getModuleName();
+    method public void setGraphPackage(String?);
+    method public void setGraphResourceName(String?);
+    method public void setModuleName(String?);
+    property public final String? graphPackage;
+    property public final String? graphResourceName;
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+    ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
+    method public String? getGraphPackage();
+    method public void setGraphPackage(String?);
+    property public final String? graphPackage;
+  }
+
+  public final class DynamicIncludeNavGraphBuilderKt {
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public class DynamicInstallManager {
+    ctor public DynamicInstallManager(android.content.Context context, com.google.android.play.core.splitinstall.SplitInstallManager splitInstallManager);
+  }
+
+  public final class DynamicInstallMonitor {
+    ctor public DynamicInstallMonitor();
+    method public void cancelInstall();
+    method public Exception? getException();
+    method public int getSessionId();
+    method public androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> getStatus();
+    method public boolean isInstallRequired();
+    property public final Exception? exception;
+    property public final boolean isInstallRequired;
+    property public final int sessionId;
+    property public final androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> status;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
+    ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public String? getProgressDestinationRoute();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    method public void setProgressDestinationRoute(String?);
+    property public final String? moduleName;
+    property public final int progressDestination;
+    property public final String? progressDestinationRoute;
+  }
+
+  public final class DynamicNavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+}
+
diff --git a/navigation/navigation-dynamic-features-runtime/api/res-2.6.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-dynamic-features-runtime/api/restricted_2.6.0-beta01.txt b/navigation/navigation-dynamic-features-runtime/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..e4c37db
--- /dev/null
+++ b/navigation/navigation-dynamic-features-runtime/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,154 @@
+// Signature format: 4.0
+package androidx.navigation.dynamicfeatures {
+
+  @androidx.navigation.Navigator.Name("activity") public final class DynamicActivityNavigator extends androidx.navigation.ActivityNavigator {
+    ctor public DynamicActivityNavigator(android.content.Context context, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination createDestination();
+  }
+
+  public static final class DynamicActivityNavigator.Destination extends androidx.navigation.ActivityNavigator.Destination {
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    ctor public DynamicActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    method public String? getModuleName();
+    method public void setModuleName(String?);
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, @IdRes int id);
+    ctor public DynamicActivityNavigatorDestinationBuilder(androidx.navigation.dynamicfeatures.DynamicActivityNavigator activityNavigator, String route);
+    method public androidx.navigation.dynamicfeatures.DynamicActivityNavigator.Destination build();
+    method public String? getAction();
+    method public String? getActivityClassName();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getModuleName();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClassName(String?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setModuleName(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final String? activityClassName;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? moduleName;
+    property public final String? targetPackage;
+  }
+
+  public final class DynamicActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class DynamicExtras implements androidx.navigation.Navigator.Extras {
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor, optional androidx.navigation.Navigator.Extras? destinationExtras);
+    ctor public DynamicExtras(optional androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor);
+    ctor public DynamicExtras();
+    method public androidx.navigation.Navigator.Extras? getDestinationExtras();
+    method public androidx.navigation.dynamicfeatures.DynamicInstallMonitor? getInstallMonitor();
+    property public final androidx.navigation.Navigator.Extras? destinationExtras;
+    property public final androidx.navigation.dynamicfeatures.DynamicInstallMonitor? installMonitor;
+  }
+
+  @androidx.navigation.Navigator.Name("navigation") public final class DynamicGraphNavigator extends androidx.navigation.NavGraphNavigator {
+    ctor public DynamicGraphNavigator(androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicGraphNavigator.DynamicNavGraph createDestination();
+    method public void installDefaultProgressDestination(kotlin.jvm.functions.Function0<? extends androidx.navigation.NavDestination> progressDestinationSupplier);
+  }
+
+  public static final class DynamicGraphNavigator.DynamicNavGraph extends androidx.navigation.NavGraph {
+    ctor public DynamicGraphNavigator.DynamicNavGraph(androidx.navigation.dynamicfeatures.DynamicGraphNavigator navGraphNavigator, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    property public final String? moduleName;
+    property public final int progressDestination;
+  }
+
+  @androidx.navigation.Navigator.Name("include-dynamic") public final class DynamicIncludeGraphNavigator extends androidx.navigation.Navigator<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor public DynamicIncludeGraphNavigator(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider, androidx.navigation.NavInflater navInflater, androidx.navigation.dynamicfeatures.DynamicInstallManager installManager);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph createDestination();
+  }
+
+  public static final class DynamicIncludeGraphNavigator.DynamicIncludeNavGraph extends androidx.navigation.NavDestination {
+    method public String? getGraphPackage();
+    method public String? getGraphResourceName();
+    method public String? getModuleName();
+    method public void setGraphPackage(String?);
+    method public void setGraphResourceName(String?);
+    method public void setModuleName(String?);
+    property public final String? graphPackage;
+    property public final String? graphResourceName;
+    property public final String? moduleName;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicIncludeNavGraphBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph> {
+    ctor @Deprecated public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, @IdRes int id, String moduleName, String graphResourceName);
+    ctor public DynamicIncludeNavGraphBuilder(androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator dynamicIncludeGraphNavigator, String route, String moduleName, String graphResourceName);
+    method public androidx.navigation.dynamicfeatures.DynamicIncludeGraphNavigator.DynamicIncludeNavGraph build();
+    method public String? getGraphPackage();
+    method public void setGraphPackage(String?);
+    property public final String? graphPackage;
+  }
+
+  public final class DynamicIncludeNavGraphBuilderKt {
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName);
+    method @Deprecated public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName);
+    method public static inline void includeDynamic(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String route, String moduleName, String graphResourceName, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicIncludeNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public class DynamicInstallManager {
+    ctor public DynamicInstallManager(android.content.Context context, com.google.android.play.core.splitinstall.SplitInstallManager splitInstallManager);
+  }
+
+  public final class DynamicInstallMonitor {
+    ctor public DynamicInstallMonitor();
+    method public void cancelInstall();
+    method public Exception? getException();
+    method public int getSessionId();
+    method public androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> getStatus();
+    method public boolean isInstallRequired();
+    property public final Exception? exception;
+    property public final boolean isInstallRequired;
+    property public final int sessionId;
+    property public final androidx.lifecycle.LiveData<com.google.android.play.core.splitinstall.SplitInstallSessionState> status;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DynamicNavGraphBuilder extends androidx.navigation.NavGraphBuilder {
+    ctor @Deprecated public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, @IdRes int id, @IdRes int startDestination);
+    ctor public DynamicNavGraphBuilder(androidx.navigation.NavigatorProvider provider, String startDestination, optional String? route);
+    method public String? getModuleName();
+    method public int getProgressDestination();
+    method public String? getProgressDestinationRoute();
+    method public void setModuleName(String?);
+    method public void setProgressDestination(int);
+    method public void setProgressDestinationRoute(String?);
+    property public final String? moduleName;
+    property public final int progressDestination;
+    property public final String? progressDestinationRoute;
+  }
+
+  public final class DynamicNavGraphBuilderKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method @Deprecated public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph navigation(androidx.navigation.NavigatorProvider, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline void navigation(androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder, String startDestination, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.dynamicfeatures.DynamicNavGraphBuilder,kotlin.Unit> builder);
+  }
+
+}
+
diff --git a/navigation/navigation-fragment-ktx/api/2.6.0-beta01.txt b/navigation/navigation-fragment-ktx/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-fragment-ktx/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-fragment-ktx/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-fragment-ktx/api/res-2.6.0-beta01.txt b/navigation/navigation-fragment-ktx/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-fragment-ktx/api/restricted_2.6.0-beta01.txt b/navigation/navigation-fragment-ktx/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-fragment-ktx/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-fragment/api/2.6.0-beta01.txt b/navigation/navigation-fragment/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..97bdfe6
--- /dev/null
+++ b/navigation/navigation-fragment/api/2.6.0-beta01.txt
@@ -0,0 +1,125 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class NavGraphViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+}
+
+package androidx.navigation.fragment {
+
+  public abstract class AbstractListDetailFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractListDetailFragment();
+    method public final androidx.navigation.fragment.NavHostFragment getDetailPaneNavHostFragment();
+    method public final androidx.slidingpanelayout.widget.SlidingPaneLayout getSlidingPaneLayout();
+    method public androidx.navigation.fragment.NavHostFragment onCreateDetailPaneNavHostFragment();
+    method public abstract android.view.View onCreateListPaneView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method public void onListPaneViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final void onViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    property public final androidx.navigation.fragment.NavHostFragment detailPaneNavHostFragment;
+    property public final androidx.slidingpanelayout.widget.SlidingPaneLayout slidingPaneLayout;
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogFragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor public DialogFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(DialogFragment::class) public static class DialogFragmentNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.DialogFragmentNavigator.Destination> fragmentNavigator);
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.DialogFragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
+  }
+
+  public final class DialogFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentKt {
+    method public static androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment);
+  }
+
+  public final class FragmentNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(androidx.fragment.app.Fragment);
+  }
+
+  @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor public FragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, int containerId);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+    method @Deprecated public androidx.fragment.app.Fragment instantiateFragment(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, String className, android.os.Bundle? args);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Fragment::class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+    property public final java.util.Map<android.view.View,java.lang.String> sharedElements;
+  }
+
+  public static final class FragmentNavigator.Extras.Builder {
+    ctor public FragmentNavigator.Extras.Builder();
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View sharedElement, String name);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String> sharedElements);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+  }
+
+  public final class FragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentNavigatorExtrasKt {
+    method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+  }
+
+  public class NavHostFragment extends androidx.fragment.app.Fragment implements androidx.navigation.NavHost {
+    ctor public NavHostFragment();
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method @Deprecated protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+    method public static final androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+    method public final androidx.navigation.NavController getNavController();
+    method @Deprecated @CallSuper protected void onCreateNavController(androidx.navigation.NavController navController);
+    method @CallSuper protected void onCreateNavHostController(androidx.navigation.NavHostController navHostController);
+    property public final androidx.navigation.NavController navController;
+    field public static final androidx.navigation.fragment.NavHostFragment.Companion Companion;
+  }
+
+  public static final class NavHostFragment.Companion {
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method public androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+  }
+
+}
+
diff --git a/navigation/navigation-fragment/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-fragment/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..97bdfe6
--- /dev/null
+++ b/navigation/navigation-fragment/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,125 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class NavGraphViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+}
+
+package androidx.navigation.fragment {
+
+  public abstract class AbstractListDetailFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractListDetailFragment();
+    method public final androidx.navigation.fragment.NavHostFragment getDetailPaneNavHostFragment();
+    method public final androidx.slidingpanelayout.widget.SlidingPaneLayout getSlidingPaneLayout();
+    method public androidx.navigation.fragment.NavHostFragment onCreateDetailPaneNavHostFragment();
+    method public abstract android.view.View onCreateListPaneView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method public void onListPaneViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final void onViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    property public final androidx.navigation.fragment.NavHostFragment detailPaneNavHostFragment;
+    property public final androidx.slidingpanelayout.widget.SlidingPaneLayout slidingPaneLayout;
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogFragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor public DialogFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(DialogFragment::class) public static class DialogFragmentNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.DialogFragmentNavigator.Destination> fragmentNavigator);
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.DialogFragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
+  }
+
+  public final class DialogFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentKt {
+    method public static androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment);
+  }
+
+  public final class FragmentNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(androidx.fragment.app.Fragment);
+  }
+
+  @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor public FragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, int containerId);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+    method @Deprecated public androidx.fragment.app.Fragment instantiateFragment(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, String className, android.os.Bundle? args);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Fragment::class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+    property public final java.util.Map<android.view.View,java.lang.String> sharedElements;
+  }
+
+  public static final class FragmentNavigator.Extras.Builder {
+    ctor public FragmentNavigator.Extras.Builder();
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View sharedElement, String name);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String> sharedElements);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+  }
+
+  public final class FragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentNavigatorExtrasKt {
+    method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+  }
+
+  public class NavHostFragment extends androidx.fragment.app.Fragment implements androidx.navigation.NavHost {
+    ctor public NavHostFragment();
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method @Deprecated protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+    method public static final androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+    method public final androidx.navigation.NavController getNavController();
+    method @Deprecated @CallSuper protected void onCreateNavController(androidx.navigation.NavController navController);
+    method @CallSuper protected void onCreateNavHostController(androidx.navigation.NavHostController navHostController);
+    property public final androidx.navigation.NavController navController;
+    field public static final androidx.navigation.fragment.NavHostFragment.Companion Companion;
+  }
+
+  public static final class NavHostFragment.Companion {
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method public androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+  }
+
+}
+
diff --git a/navigation/navigation-fragment/api/res-2.6.0-beta01.txt b/navigation/navigation-fragment/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-fragment/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-fragment/api/restricted_2.6.0-beta01.txt b/navigation/navigation-fragment/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..97bdfe6
--- /dev/null
+++ b/navigation/navigation-fragment/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,125 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class NavGraphViewModelLazyKt {
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, @IdRes int navGraphId, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @Deprecated @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM> navGraphViewModels(androidx.fragment.app.Fragment, String navGraphRoute, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.viewmodel.CreationExtras>? extrasProducer, optional kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer);
+  }
+
+}
+
+package androidx.navigation.fragment {
+
+  public abstract class AbstractListDetailFragment extends androidx.fragment.app.Fragment {
+    ctor public AbstractListDetailFragment();
+    method public final androidx.navigation.fragment.NavHostFragment getDetailPaneNavHostFragment();
+    method public final androidx.slidingpanelayout.widget.SlidingPaneLayout getSlidingPaneLayout();
+    method public androidx.navigation.fragment.NavHostFragment onCreateDetailPaneNavHostFragment();
+    method public abstract android.view.View onCreateListPaneView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup? container, android.os.Bundle? savedInstanceState);
+    method public void onListPaneViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    method @CallSuper public final void onViewCreated(android.view.View view, android.os.Bundle? savedInstanceState);
+    property public final androidx.navigation.fragment.NavHostFragment detailPaneNavHostFragment;
+    property public final androidx.slidingpanelayout.widget.SlidingPaneLayout slidingPaneLayout;
+  }
+
+  @androidx.navigation.Navigator.Name("dialog") public final class DialogFragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor public DialogFragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination createDestination();
+  }
+
+  @androidx.navigation.NavDestination.ClassType(DialogFragment::class) public static class DialogFragmentNavigator.Destination extends androidx.navigation.NavDestination implements androidx.navigation.FloatingWindow {
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.DialogFragmentNavigator.Destination> fragmentNavigator);
+    ctor public DialogFragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.DialogFragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class DialogFragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.DialogFragmentNavigator.Destination> {
+    ctor @Deprecated public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    ctor public DialogFragmentNavigatorDestinationBuilder(androidx.navigation.fragment.DialogFragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.DialogFragment> fragmentClass);
+    method public androidx.navigation.fragment.DialogFragmentNavigator.Destination build();
+  }
+
+  public final class DialogFragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.DialogFragment> void dialog(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.DialogFragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentKt {
+    method public static androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment);
+  }
+
+  public final class FragmentNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(androidx.fragment.app.Fragment);
+  }
+
+  @androidx.navigation.Navigator.Name("fragment") public class FragmentNavigator extends androidx.navigation.Navigator<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor public FragmentNavigator(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, int containerId);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination createDestination();
+    method @Deprecated public androidx.fragment.app.Fragment instantiateFragment(android.content.Context context, androidx.fragment.app.FragmentManager fragmentManager, String className, android.os.Bundle? args);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Fragment::class) public static class FragmentNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public FragmentNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> fragmentNavigator);
+    ctor public FragmentNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String getClassName();
+    method public final androidx.navigation.fragment.FragmentNavigator.Destination setClassName(String className);
+    property public final String className;
+  }
+
+  public static final class FragmentNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public java.util.Map<android.view.View,java.lang.String> getSharedElements();
+    property public final java.util.Map<android.view.View,java.lang.String> sharedElements;
+  }
+
+  public static final class FragmentNavigator.Extras.Builder {
+    ctor public FragmentNavigator.Extras.Builder();
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElement(android.view.View sharedElement, String name);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras.Builder addSharedElements(java.util.Map<android.view.View,java.lang.String> sharedElements);
+    method public androidx.navigation.fragment.FragmentNavigator.Extras build();
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class FragmentNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.fragment.FragmentNavigator.Destination> {
+    ctor @Deprecated public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, @IdRes int id, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    ctor public FragmentNavigatorDestinationBuilder(androidx.navigation.fragment.FragmentNavigator navigator, String route, kotlin.reflect.KClass<? extends androidx.fragment.app.Fragment> fragmentClass);
+    method public androidx.navigation.fragment.FragmentNavigator.Destination build();
+  }
+
+  public final class FragmentNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id);
+    method @Deprecated public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> void fragment(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.fragment.FragmentNavigatorDestinationBuilder,? extends kotlin.Unit> builder);
+  }
+
+  public final class FragmentNavigatorExtrasKt {
+    method public static androidx.navigation.fragment.FragmentNavigator.Extras FragmentNavigatorExtras(kotlin.Pair<? extends android.view.View,java.lang.String>... sharedElements);
+  }
+
+  public class NavHostFragment extends androidx.fragment.app.Fragment implements androidx.navigation.NavHost {
+    ctor public NavHostFragment();
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public static final androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method @Deprecated protected androidx.navigation.Navigator<? extends androidx.navigation.fragment.FragmentNavigator.Destination> createFragmentNavigator();
+    method public static final androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+    method public final androidx.navigation.NavController getNavController();
+    method @Deprecated @CallSuper protected void onCreateNavController(androidx.navigation.NavController navController);
+    method @CallSuper protected void onCreateNavHostController(androidx.navigation.NavHostController navHostController);
+    property public final androidx.navigation.NavController navController;
+    field public static final androidx.navigation.fragment.NavHostFragment.Companion Companion;
+  }
+
+  public static final class NavHostFragment.Companion {
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId, optional android.os.Bundle? startDestinationArgs);
+    method public androidx.navigation.fragment.NavHostFragment create(@NavigationRes int graphResId);
+    method public androidx.navigation.NavController findNavController(androidx.fragment.app.Fragment fragment);
+  }
+
+}
+
diff --git a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorTest.kt b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorTest.kt
index 5e8e6b0..dc60ee0 100644
--- a/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorTest.kt
+++ b/navigation/navigation-fragment/src/androidTest/java/androidx/navigation/fragment/FragmentNavigatorTest.kt
@@ -53,6 +53,7 @@
 import androidx.testutils.withUse
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.lang.IllegalArgumentException
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import kotlin.reflect.KClass
@@ -555,7 +556,7 @@
 
     @UiThreadTest
     @Test
-    fun testNavigateAndAddIndependentFragment() {
+    fun testNavigationAndAddIndependentFragmentWithoutBackStack() {
         val entry = createBackStackEntry()
 
         fragmentNavigator.navigate(listOf(entry), null, null)
@@ -584,6 +585,42 @@
             .isEqualTo(independentFragment)
     }
 
+    @UiThreadTest
+    @Test
+    fun testNavigateAndAddIndependentFragmentWithBackStack() {
+        val entry = createBackStackEntry()
+
+        fragmentNavigator.navigate(listOf(entry), null, null)
+        assertThat(navigatorState.backStack.value)
+            .containsExactly(entry)
+        fragmentManager.executePendingTransactions()
+        val fragment = fragmentManager.findFragmentById(R.id.container)
+        assertWithMessage("Fragment should be added")
+            .that(fragment)
+            .isNotNull()
+        assertWithMessage("Fragment should be the correct type")
+            .that(fragment)
+            .isInstanceOf(EmptyFragment::class.java)
+        assertWithMessage("Fragment should be the primary navigation Fragment")
+            .that(fragmentManager.primaryNavigationFragment)
+            .isSameInstanceAs(fragment)
+
+        val independentFragment = EmptyFragment()
+        fragmentManager.beginTransaction()
+            .replace(R.id.container, independentFragment)
+            .addToBackStack(null)
+            .commit()
+        try {
+            fragmentManager.executePendingTransactions()
+        } catch (e: IllegalArgumentException) {
+            assertWithMessage("adding a fragment to the back stack manually should fail")
+                .that(e.message)
+                .contains("The fragment " + independentFragment + " is unknown to the " +
+                    "FragmentNavigator. Please use the navigate() function to add fragments to " +
+                    "the FragmentNavigator managed FragmentManager.")
+        }
+    }
+
     @LargeTest
     @UiThreadTest
     @Test
@@ -1244,7 +1281,9 @@
         }
 
         // navigate to first entry and verify it executed correctly
-        fragmentNavigator.navigate(listOf(entry1), options, null)
+        activityRule.runOnUiThread {
+            fragmentNavigator.navigate(listOf(entry1), options, null)
+        }
         assertThat(navigatorState.backStack.value).containsExactly(entry1)
         activityRule.runOnUiThread {
             fragmentManager.executePendingTransactions()
@@ -1255,30 +1294,122 @@
             .isNotNull()
 
         // navigate to the second entry and pop it back to back.
-        fragmentNavigator.navigate(listOf(entry2), options, null)
-        fragmentNavigator.popBackStack(entry2, false)
+        activityRule.runOnUiThread {
+            fragmentNavigator.navigate(listOf(entry2), options, null)
+            fragmentManager.executePendingTransactions()
+            fragmentNavigator.popBackStack(entry2, false)
+        }
         assertThat(navigatorState.backStack.value).containsExactly(entry1)
         activityRule.runOnUiThread {
             fragmentManager.executePendingTransactions()
         }
-        val fragment1 = fragmentManager.findFragmentById(R.id.container)
-        assertWithMessage("Fragment should be added")
-            .that(fragment1)
-            .isNotNull()
 
         // Add an observer to ensure that we don't attempt to verify the state until animations
         // are complete and the viewLifecycle has been RESUMED.
-        val countDownLatch = CountDownLatch(1)
+        val viewCountDownLatch = CountDownLatch(1)
+        val entryCountDownLatch = CountDownLatch(1)
         activityRule.runOnUiThread {
-            fragment1?.viewLifecycleOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
+            fragment?.viewLifecycleOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
                 override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                     if (event == Lifecycle.Event.ON_RESUME) {
-                        countDownLatch.countDown()
+                        viewCountDownLatch.countDown()
+                    }
+                }
+            })
+            entry1.lifecycle.addObserver(object : LifecycleEventObserver {
+                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+                    if (event == Lifecycle.Event.ON_RESUME) {
+                        entryCountDownLatch.countDown()
                     }
                 }
             })
         }
-        assertThat(countDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        assertThat(viewCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        assertThat(entryCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        // Entry 1 should move back to RESUMED
+        assertThat(entry1.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
+        // Entry 2 should be DESTROYED
+        assertThat(entry2.lifecycle.currentState).isEqualTo(Lifecycle.State.DESTROYED)
+
+        // verify that the first entry made it down to CREATED
+        assertWithMessage("Entry2 should have been stopped").that(entry1Stopped).isTrue()
+    }
+
+    @LargeTest
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    fun testNavigatePopInterruptSameFrame() {
+        val entry1 = createBackStackEntry(clazz = AnimatorFragment::class)
+        var entry1Stopped = false
+
+        // Add observer to entry to verify lifecycle events.
+        activityRule.runOnUiThread {
+            entry1.lifecycle.addObserver(object : LifecycleEventObserver {
+                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+                    if (event == Lifecycle.Event.ON_STOP) {
+                        entry1Stopped = true
+                    }
+                }
+            })
+        }
+
+        val entry2 = createBackStackEntry(SECOND_FRAGMENT, clazz = AnimatorFragment::class)
+
+        val options = navOptions {
+            anim {
+                enter = R.animator.fade_enter
+                exit = R.animator.fade_exit
+                popEnter = R.animator.fade_enter
+                popExit = R.animator.fade_exit
+            }
+        }
+
+        // navigate to first entry and verify it executed correctly
+        activityRule.runOnUiThread {
+            fragmentNavigator.navigate(listOf(entry1), options, null)
+        }
+        assertThat(navigatorState.backStack.value).containsExactly(entry1)
+        activityRule.runOnUiThread {
+            fragmentManager.executePendingTransactions()
+        }
+        val fragment = fragmentManager.findFragmentById(R.id.container)
+        assertWithMessage("Fragment should be added")
+            .that(fragment)
+            .isNotNull()
+
+        // navigate to the second entry and pop it back to back.
+        activityRule.runOnUiThread {
+            fragmentNavigator.navigate(listOf(entry2), options, null)
+            fragmentNavigator.popBackStack(entry2, false)
+        }
+        assertThat(navigatorState.backStack.value).containsExactly(entry1)
+        activityRule.runOnUiThread {
+            fragmentManager.executePendingTransactions()
+        }
+
+        // Add an observer to ensure that we don't attempt to verify the state until animations
+        // are complete and the viewLifecycle has been RESUMED.
+        val viewCountDownLatch = CountDownLatch(1)
+        val entryCountDownLatch = CountDownLatch(1)
+        activityRule.runOnUiThread {
+            fragment?.viewLifecycleOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
+                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+                    if (event == Lifecycle.Event.ON_RESUME) {
+                        viewCountDownLatch.countDown()
+                    }
+                }
+            })
+            entry1.lifecycle.addObserver(object : LifecycleEventObserver {
+                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+                    if (event == Lifecycle.Event.ON_RESUME) {
+                        entryCountDownLatch.countDown()
+                    }
+                }
+            })
+        }
+
+        assertThat(viewCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        assertThat(entryCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
         // Entry 1 should move back to RESUMED
         assertThat(entry1.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
         // Entry 2 should be DESTROYED
diff --git a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigator.kt b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigator.kt
index 48378f5..f3aafc6 100644
--- a/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigator.kt
+++ b/navigation/navigation-fragment/src/main/java/androidx/navigation/fragment/FragmentNavigator.kt
@@ -32,6 +32,9 @@
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewmodel.CreationExtras
+import androidx.lifecycle.viewmodel.initializer
+import androidx.lifecycle.viewmodel.viewModelFactory
 import androidx.navigation.NavBackStackEntry
 import androidx.navigation.NavDestination
 import androidx.navigation.NavOptions
@@ -88,25 +91,38 @@
         }
     }
 
+    private val fragmentViewObserver = { entry: NavBackStackEntry ->
+        object : LifecycleEventObserver {
+            override fun onStateChanged(
+                source: LifecycleOwner,
+                event: Lifecycle.Event
+            ) {
+                // Once the lifecycle reaches RESUMED, we can mark the transition complete
+                if (event == Lifecycle.Event.ON_RESUME) {
+                    state.markTransitionComplete(entry)
+                }
+                // Once the lifecycle reaches DESTROYED, we can mark the transition complete and
+                // remove the observer.
+                if (event == Lifecycle.Event.ON_DESTROY) {
+                    entriesToPop.remove(entry.id)
+                    state.markTransitionComplete(entry)
+                    source.lifecycle.removeObserver(this)
+                }
+            }
+        }
+    }
+
     override fun onAttach(state: NavigatorState) {
         super.onAttach(state)
 
         fragmentManager.addFragmentOnAttachListener { _, fragment ->
             val entry = state.backStack.value.lastOrNull { it.id == fragment.tag }
             if (entry != null) {
-                fragment.viewLifecycleOwnerLiveData.observe(fragment) { owner ->
-                    // attach observer unless it was already popped at this point
-                    if (owner != null && !entriesToPop.contains(fragment.tag)) {
-                        attachObserver(entry, fragment)
-                    }
-                }
-                fragment.lifecycle.addObserver(fragmentObserver)
+                attachObservers(entry, fragment)
                 // We need to ensure that if the fragment has its state saved and then that state
                 // later cleared without the restoring the fragment that we also clear the state
                 // of the associated entry.
-                val viewModel = ViewModelProvider(fragment)[ClearEntryStateViewModel::class.java]
-                viewModel.completeTransition =
-                    WeakReference { entry.let { state.markTransitionComplete(it) } }
+                attachClearViewModel(fragment, entry, state)
             }
         }
 
@@ -127,50 +143,69 @@
                 val entry = (state.backStack.value + state.transitionsInProgress.value).lastOrNull {
                     it.id == fragment.tag
                 }
-                if (pop && entry != null) {
-                    // The entry has already been removed from the back stack so just remove it
-                    // from the list
-                    if (!state.backStack.value.contains(entry)) {
-                        // remove it so we don't falsely identify a direct call to popBackStack
-                        entriesToPop.remove(entry.id)
+                if (!pop) {
+                    requireNotNull(entry) {
+                        "The fragment " + fragment + " is unknown to the FragmentNavigator. " +
+                            "Please use the navigate() function to add fragments to the " +
+                            "FragmentNavigator managed FragmentManager."
                     }
-                    // This is the case of system back where we will need to make the call to
-                    // popBackStack. Otherwise, popBackStack was called directly and this should
-                    // end up being a no-op.
-                    else if (entriesToPop.isEmpty() && fragment.isRemoving) {
-                        state.popWithTransition(entry, false)
+                }
+                if (entry != null) {
+                    // In case we get a fragment that was never attached to the fragment manager,
+                    // we need to make sure we still return the entries to their proper final state.
+                    attachClearViewModel(fragment, entry, state)
+                    if (pop) {
+                        // The entry has already been removed from the back stack so just remove it
+                        // from the list
+                        if (!state.backStack.value.contains(entry)) {
+                            // remove it so we don't falsely identify a direct call to popBackStack
+                            entriesToPop.remove(entry.id)
+                        }
+                        // This is the case of system back where we will need to make the call to
+                        // popBackStack. Otherwise, popBackStack was called directly and this should
+                        // end up being a no-op.
+                        else if (entriesToPop.isEmpty() && fragment.isRemoving) {
+                            state.popWithTransition(entry, false)
+                        }
                     }
                 }
             }
         })
     }
 
-    private fun attachObserver(entry: NavBackStackEntry, fragment: Fragment) {
-        val viewLifecycle = fragment.viewLifecycleOwner.lifecycle
-        val currentState = viewLifecycle.currentState
-        // We only need to add observers while the viewLifecycle has not reached a final
-        // state
-        if (currentState.isAtLeast(Lifecycle.State.CREATED)) {
-            viewLifecycle.addObserver(object : LifecycleEventObserver {
-                override fun onStateChanged(
-                    source: LifecycleOwner,
-                    event: Lifecycle.Event
-                ) {
-                    // Once the lifecycle reaches RESUMED, we can mark the transition
-                    // complete
-                    if (event == Lifecycle.Event.ON_RESUME) {
+    private fun attachObservers(entry: NavBackStackEntry, fragment: Fragment) {
+        fragment.viewLifecycleOwnerLiveData.observe(fragment) { owner ->
+            // attach observer unless it was already popped at this point
+            if (owner != null && !entriesToPop.contains(fragment.tag)) {
+                val viewLifecycle = fragment.viewLifecycleOwner.lifecycle
+                // We only need to add observers while the viewLifecycle has not reached a final
+                // state
+                if (viewLifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
+                    viewLifecycle.addObserver(fragmentViewObserver(entry))
+                }
+            }
+        }
+        fragment.lifecycle.addObserver(fragmentObserver)
+    }
+
+    internal fun attachClearViewModel(
+        fragment: Fragment,
+        entry: NavBackStackEntry,
+        state: NavigatorState
+    ) {
+        val viewModel = ViewModelProvider(
+            fragment.viewModelStore,
+            viewModelFactory { initializer { ClearEntryStateViewModel() } },
+            CreationExtras.Empty
+        )[ClearEntryStateViewModel::class.java]
+        viewModel.completeTransition =
+            WeakReference {
+                entry.let {
+                    state.transitionsInProgress.value.forEach { entry ->
                         state.markTransitionComplete(entry)
                     }
-                    // Once the lifecycle reaches DESTROYED, we can mark the transition
-                    // complete and remove the observer.
-                    if (event == Lifecycle.Event.ON_DESTROY) {
-                        entriesToPop.remove(entry.id)
-                        state.markTransitionComplete(entry)
-                        viewLifecycle.removeObserver(this)
-                    }
                 }
-            })
-        }
+            }
     }
 
     /**
diff --git a/navigation/navigation-runtime-ktx/api/2.6.0-beta01.txt b/navigation/navigation-runtime-ktx/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-runtime-ktx/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-runtime-ktx/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-runtime-ktx/api/res-2.6.0-beta01.txt b/navigation/navigation-runtime-ktx/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-runtime-ktx/api/restricted_2.6.0-beta01.txt b/navigation/navigation-runtime-ktx/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-runtime-ktx/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-runtime/api/2.6.0-beta01.txt b/navigation/navigation-runtime/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..39d9a7f
--- /dev/null
+++ b/navigation/navigation-runtime/api/2.6.0-beta01.txt
@@ -0,0 +1,224 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActivityKt {
+    method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+  }
+
+  public final class ActivityNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(android.app.Activity);
+  }
+
+  @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+    ctor public ActivityNavigator(android.content.Context context);
+    method public static final void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+    method public androidx.navigation.ActivityNavigator.Destination createDestination();
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    field public static final androidx.navigation.ActivityNavigator.Companion Companion;
+  }
+
+  public static final class ActivityNavigator.Companion {
+    method public void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Activity::class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String? getAction();
+    method public final android.content.ComponentName? getComponent();
+    method public final android.net.Uri? getData();
+    method public final String? getDataPattern();
+    method public final android.content.Intent? getIntent();
+    method public final String? getTargetPackage();
+    method public final androidx.navigation.ActivityNavigator.Destination setAction(String? action);
+    method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName? name);
+    method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri? data);
+    method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String? dataPattern);
+    method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent? intent);
+    method public final androidx.navigation.ActivityNavigator.Destination setTargetPackage(String? packageName);
+    property public final String? action;
+    property public final android.content.ComponentName? component;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final android.content.Intent? intent;
+    property public final String? targetPackage;
+  }
+
+  public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public androidx.core.app.ActivityOptionsCompat? getActivityOptions();
+    method public int getFlags();
+    property public final androidx.core.app.ActivityOptionsCompat? activityOptions;
+    property public final int flags;
+  }
+
+  public static final class ActivityNavigator.Extras.Builder {
+    ctor public ActivityNavigator.Extras.Builder();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int flags);
+    method public androidx.navigation.ActivityNavigator.Extras build();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(androidx.core.app.ActivityOptionsCompat activityOptions);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+    ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
+    method public androidx.navigation.ActivityNavigator.Destination build();
+    method public String? getAction();
+    method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? targetPackage;
+  }
+
+  public final class ActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class ActivityNavigatorExtrasKt {
+    method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(optional androidx.core.app.ActivityOptionsCompat? activityOptions, optional int flags);
+  }
+
+  public class NavController {
+    ctor public NavController(android.content.Context context);
+    method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @MainThread public final boolean clearBackStack(String route);
+    method @MainThread public final boolean clearBackStack(@IdRes int destinationId);
+    method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+    method public androidx.navigation.NavBackStackEntry getBackStackEntry(@IdRes int destinationId);
+    method public final androidx.navigation.NavBackStackEntry getBackStackEntry(String route);
+    method public androidx.navigation.NavBackStackEntry? getCurrentBackStackEntry();
+    method public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> getCurrentBackStackEntryFlow();
+    method public androidx.navigation.NavDestination? getCurrentDestination();
+    method @MainThread public androidx.navigation.NavGraph getGraph();
+    method public androidx.navigation.NavInflater getNavInflater();
+    method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+    method public androidx.navigation.NavBackStackEntry? getPreviousBackStackEntry();
+    method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
+    method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+    method @MainThread public void navigate(@IdRes int resId);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(android.net.Uri deepLink);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.Navigator.Extras navigatorExtras);
+    method @MainThread public final void navigate(String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions, optional androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions);
+    method @MainThread public final void navigate(String route);
+    method @MainThread public boolean navigateUp();
+    method @MainThread public boolean popBackStack();
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive);
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive, boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive, optional boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive);
+    method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @CallSuper public void restoreState(android.os.Bundle? navState);
+    method @CallSuper public android.os.Bundle? saveState();
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId, android.os.Bundle? startDestinationArgs);
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph graph, android.os.Bundle? startDestinationArgs);
+    property public androidx.navigation.NavBackStackEntry? currentBackStackEntry;
+    property public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> currentBackStackEntryFlow;
+    property public androidx.navigation.NavDestination? currentDestination;
+    property @MainThread public androidx.navigation.NavGraph graph;
+    property public androidx.navigation.NavInflater navInflater;
+    property public androidx.navigation.NavigatorProvider navigatorProvider;
+    property public androidx.navigation.NavBackStackEntry? previousBackStackEntry;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> visibleEntries;
+    field public static final androidx.navigation.NavController.Companion Companion;
+    field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+  }
+
+  public static final class NavController.Companion {
+  }
+
+  public static fun interface NavController.OnDestinationChangedListener {
+    method public void onDestinationChanged(androidx.navigation.NavController controller, androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavDeepLinkBuilder {
+    ctor public NavDeepLinkBuilder(android.content.Context context);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route);
+    method public android.app.PendingIntent createPendingIntent();
+    method public androidx.core.app.TaskStackBuilder createTaskStackBuilder();
+    method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity> activityClass);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName componentName);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int navGraphId);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph navGraph);
+  }
+
+  public interface NavHost {
+    method public androidx.navigation.NavController getNavController();
+    property public abstract androidx.navigation.NavController navController;
+  }
+
+  public class NavHostController extends androidx.navigation.NavController {
+    ctor public NavHostController(android.content.Context context);
+    method public final void enableOnBackPressed(boolean enabled);
+    method public final void setLifecycleOwner(androidx.lifecycle.LifecycleOwner owner);
+    method public final void setOnBackPressedDispatcher(androidx.activity.OnBackPressedDispatcher dispatcher);
+    method public final void setViewModelStore(androidx.lifecycle.ViewModelStore viewModelStore);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavInflater {
+    ctor public NavInflater(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph inflate(@NavigationRes int graphResId);
+    field public static final androidx.navigation.NavInflater.Companion Companion;
+  }
+
+  public static final class NavInflater.Companion {
+  }
+
+  public final class Navigation {
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId, optional android.os.Bundle? args);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(androidx.navigation.NavDirections directions);
+    method public static androidx.navigation.NavController findNavController(android.app.Activity activity, @IdRes int viewId);
+    method public static androidx.navigation.NavController findNavController(android.view.View view);
+    method public static void setViewNavController(android.view.View view, androidx.navigation.NavController? controller);
+    field public static final androidx.navigation.Navigation INSTANCE;
+  }
+
+  public final class ViewKt {
+    method public static androidx.navigation.NavController findNavController(android.view.View);
+  }
+
+}
+
diff --git a/navigation/navigation-runtime/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-runtime/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..6faf37c
--- /dev/null
+++ b/navigation/navigation-runtime/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,229 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActivityKt {
+    method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+  }
+
+  public final class ActivityNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(android.app.Activity);
+  }
+
+  @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+    ctor public ActivityNavigator(android.content.Context context);
+    method public static final void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+    method public androidx.navigation.ActivityNavigator.Destination createDestination();
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    field public static final androidx.navigation.ActivityNavigator.Companion Companion;
+  }
+
+  public static final class ActivityNavigator.Companion {
+    method public void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Activity::class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String? getAction();
+    method public final android.content.ComponentName? getComponent();
+    method public final android.net.Uri? getData();
+    method public final String? getDataPattern();
+    method public final android.content.Intent? getIntent();
+    method public final String? getTargetPackage();
+    method public final androidx.navigation.ActivityNavigator.Destination setAction(String? action);
+    method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName? name);
+    method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri? data);
+    method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String? dataPattern);
+    method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent? intent);
+    method public final androidx.navigation.ActivityNavigator.Destination setTargetPackage(String? packageName);
+    property public final String? action;
+    property public final android.content.ComponentName? component;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final android.content.Intent? intent;
+    property public final String? targetPackage;
+  }
+
+  public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public androidx.core.app.ActivityOptionsCompat? getActivityOptions();
+    method public int getFlags();
+    property public final androidx.core.app.ActivityOptionsCompat? activityOptions;
+    property public final int flags;
+  }
+
+  public static final class ActivityNavigator.Extras.Builder {
+    ctor public ActivityNavigator.Extras.Builder();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int flags);
+    method public androidx.navigation.ActivityNavigator.Extras build();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(androidx.core.app.ActivityOptionsCompat activityOptions);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+    ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
+    method public androidx.navigation.ActivityNavigator.Destination build();
+    method public String? getAction();
+    method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? targetPackage;
+  }
+
+  public final class ActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class ActivityNavigatorExtrasKt {
+    method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(optional androidx.core.app.ActivityOptionsCompat? activityOptions, optional int flags);
+  }
+
+  public class NavController {
+    ctor public NavController(android.content.Context context);
+    method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @MainThread public final boolean clearBackStack(String route);
+    method @MainThread public final boolean clearBackStack(@IdRes int destinationId);
+    method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+    method @androidx.navigation.NavDeepLinkSaveStateControl public static final void enableDeepLinkSaveState(boolean saveState);
+    method public androidx.navigation.NavBackStackEntry getBackStackEntry(@IdRes int destinationId);
+    method public final androidx.navigation.NavBackStackEntry getBackStackEntry(String route);
+    method public androidx.navigation.NavBackStackEntry? getCurrentBackStackEntry();
+    method public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> getCurrentBackStackEntryFlow();
+    method public androidx.navigation.NavDestination? getCurrentDestination();
+    method @MainThread public androidx.navigation.NavGraph getGraph();
+    method public androidx.navigation.NavInflater getNavInflater();
+    method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+    method public androidx.navigation.NavBackStackEntry? getPreviousBackStackEntry();
+    method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
+    method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+    method @MainThread public void navigate(@IdRes int resId);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(android.net.Uri deepLink);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.Navigator.Extras navigatorExtras);
+    method @MainThread public final void navigate(String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions, optional androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions);
+    method @MainThread public final void navigate(String route);
+    method @MainThread public boolean navigateUp();
+    method @MainThread public boolean popBackStack();
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive);
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive, boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive, optional boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive);
+    method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @CallSuper public void restoreState(android.os.Bundle? navState);
+    method @CallSuper public android.os.Bundle? saveState();
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId, android.os.Bundle? startDestinationArgs);
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph graph, android.os.Bundle? startDestinationArgs);
+    property public androidx.navigation.NavBackStackEntry? currentBackStackEntry;
+    property public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> currentBackStackEntryFlow;
+    property public androidx.navigation.NavDestination? currentDestination;
+    property @MainThread public androidx.navigation.NavGraph graph;
+    property public androidx.navigation.NavInflater navInflater;
+    property public androidx.navigation.NavigatorProvider navigatorProvider;
+    property public androidx.navigation.NavBackStackEntry? previousBackStackEntry;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> visibleEntries;
+    field public static final androidx.navigation.NavController.Companion Companion;
+    field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+  }
+
+  public static final class NavController.Companion {
+    method @androidx.navigation.NavDeepLinkSaveStateControl public void enableDeepLinkSaveState(boolean saveState);
+  }
+
+  public static fun interface NavController.OnDestinationChangedListener {
+    method public void onDestinationChanged(androidx.navigation.NavController controller, androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavDeepLinkBuilder {
+    ctor public NavDeepLinkBuilder(android.content.Context context);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route);
+    method public android.app.PendingIntent createPendingIntent();
+    method public androidx.core.app.TaskStackBuilder createTaskStackBuilder();
+    method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity> activityClass);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName componentName);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int navGraphId);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph navGraph);
+  }
+
+  @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavDeepLinkSaveStateControl {
+  }
+
+  public interface NavHost {
+    method public androidx.navigation.NavController getNavController();
+    property public abstract androidx.navigation.NavController navController;
+  }
+
+  public class NavHostController extends androidx.navigation.NavController {
+    ctor public NavHostController(android.content.Context context);
+    method public final void enableOnBackPressed(boolean enabled);
+    method public final void setLifecycleOwner(androidx.lifecycle.LifecycleOwner owner);
+    method public final void setOnBackPressedDispatcher(androidx.activity.OnBackPressedDispatcher dispatcher);
+    method public final void setViewModelStore(androidx.lifecycle.ViewModelStore viewModelStore);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavInflater {
+    ctor public NavInflater(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph inflate(@NavigationRes int graphResId);
+    field public static final androidx.navigation.NavInflater.Companion Companion;
+  }
+
+  public static final class NavInflater.Companion {
+  }
+
+  public final class Navigation {
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId, optional android.os.Bundle? args);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(androidx.navigation.NavDirections directions);
+    method public static androidx.navigation.NavController findNavController(android.app.Activity activity, @IdRes int viewId);
+    method public static androidx.navigation.NavController findNavController(android.view.View view);
+    method public static void setViewNavController(android.view.View view, androidx.navigation.NavController? controller);
+    field public static final androidx.navigation.Navigation INSTANCE;
+  }
+
+  public final class ViewKt {
+    method public static androidx.navigation.NavController findNavController(android.view.View);
+  }
+
+}
+
diff --git a/navigation/navigation-runtime/api/res-2.6.0-beta01.txt b/navigation/navigation-runtime/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-runtime/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-runtime/api/restricted_2.6.0-beta01.txt b/navigation/navigation-runtime/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..39d9a7f
--- /dev/null
+++ b/navigation/navigation-runtime/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,224 @@
+// Signature format: 4.0
+package androidx.navigation {
+
+  public final class ActivityKt {
+    method public static androidx.navigation.NavController findNavController(android.app.Activity, @IdRes int viewId);
+  }
+
+  public final class ActivityNavArgsLazyKt {
+    method @MainThread public static inline <reified Args extends androidx.navigation.NavArgs> androidx.navigation.NavArgsLazy<Args> navArgs(android.app.Activity);
+  }
+
+  @androidx.navigation.Navigator.Name("activity") public class ActivityNavigator extends androidx.navigation.Navigator<androidx.navigation.ActivityNavigator.Destination> {
+    ctor public ActivityNavigator(android.content.Context context);
+    method public static final void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+    method public androidx.navigation.ActivityNavigator.Destination createDestination();
+    method public androidx.navigation.NavDestination? navigate(androidx.navigation.ActivityNavigator.Destination destination, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    field public static final androidx.navigation.ActivityNavigator.Companion Companion;
+  }
+
+  public static final class ActivityNavigator.Companion {
+    method public void applyPopAnimationsToPendingTransition(android.app.Activity activity);
+  }
+
+  @androidx.navigation.NavDestination.ClassType(Activity::class) public static class ActivityNavigator.Destination extends androidx.navigation.NavDestination {
+    ctor public ActivityNavigator.Destination(androidx.navigation.Navigator<? extends androidx.navigation.ActivityNavigator.Destination> activityNavigator);
+    ctor public ActivityNavigator.Destination(androidx.navigation.NavigatorProvider navigatorProvider);
+    method public final String? getAction();
+    method public final android.content.ComponentName? getComponent();
+    method public final android.net.Uri? getData();
+    method public final String? getDataPattern();
+    method public final android.content.Intent? getIntent();
+    method public final String? getTargetPackage();
+    method public final androidx.navigation.ActivityNavigator.Destination setAction(String? action);
+    method public final androidx.navigation.ActivityNavigator.Destination setComponentName(android.content.ComponentName? name);
+    method public final androidx.navigation.ActivityNavigator.Destination setData(android.net.Uri? data);
+    method public final androidx.navigation.ActivityNavigator.Destination setDataPattern(String? dataPattern);
+    method public final androidx.navigation.ActivityNavigator.Destination setIntent(android.content.Intent? intent);
+    method public final androidx.navigation.ActivityNavigator.Destination setTargetPackage(String? packageName);
+    property public final String? action;
+    property public final android.content.ComponentName? component;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final android.content.Intent? intent;
+    property public final String? targetPackage;
+  }
+
+  public static final class ActivityNavigator.Extras implements androidx.navigation.Navigator.Extras {
+    method public androidx.core.app.ActivityOptionsCompat? getActivityOptions();
+    method public int getFlags();
+    property public final androidx.core.app.ActivityOptionsCompat? activityOptions;
+    property public final int flags;
+  }
+
+  public static final class ActivityNavigator.Extras.Builder {
+    ctor public ActivityNavigator.Extras.Builder();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder addFlags(int flags);
+    method public androidx.navigation.ActivityNavigator.Extras build();
+    method public androidx.navigation.ActivityNavigator.Extras.Builder setActivityOptions(androidx.core.app.ActivityOptionsCompat activityOptions);
+  }
+
+  @androidx.navigation.NavDestinationDsl public final class ActivityNavigatorDestinationBuilder extends androidx.navigation.NavDestinationBuilder<androidx.navigation.ActivityNavigator.Destination> {
+    ctor @Deprecated public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, @IdRes int id);
+    ctor public ActivityNavigatorDestinationBuilder(androidx.navigation.ActivityNavigator navigator, String route);
+    method public androidx.navigation.ActivityNavigator.Destination build();
+    method public String? getAction();
+    method public kotlin.reflect.KClass<? extends android.app.Activity>? getActivityClass();
+    method public android.net.Uri? getData();
+    method public String? getDataPattern();
+    method public String? getTargetPackage();
+    method public void setAction(String?);
+    method public void setActivityClass(kotlin.reflect.KClass<? extends android.app.Activity>?);
+    method public void setData(android.net.Uri?);
+    method public void setDataPattern(String?);
+    method public void setTargetPackage(String?);
+    property public final String? action;
+    property public final kotlin.reflect.KClass<? extends android.app.Activity>? activityClass;
+    property public final android.net.Uri? data;
+    property public final String? dataPattern;
+    property public final String? targetPackage;
+  }
+
+  public final class ActivityNavigatorDestinationBuilderKt {
+    method @Deprecated public static inline void activity(androidx.navigation.NavGraphBuilder, @IdRes int id, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+    method public static inline void activity(androidx.navigation.NavGraphBuilder, String route, kotlin.jvm.functions.Function1<? super androidx.navigation.ActivityNavigatorDestinationBuilder,kotlin.Unit> builder);
+  }
+
+  public final class ActivityNavigatorExtrasKt {
+    method public static androidx.navigation.ActivityNavigator.Extras ActivityNavigatorExtras(optional androidx.core.app.ActivityOptionsCompat? activityOptions, optional int flags);
+  }
+
+  public class NavController {
+    ctor public NavController(android.content.Context context);
+    method public void addOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @MainThread public final boolean clearBackStack(String route);
+    method @MainThread public final boolean clearBackStack(@IdRes int destinationId);
+    method public androidx.navigation.NavDeepLinkBuilder createDeepLink();
+    method public androidx.navigation.NavBackStackEntry getBackStackEntry(@IdRes int destinationId);
+    method public final androidx.navigation.NavBackStackEntry getBackStackEntry(String route);
+    method public androidx.navigation.NavBackStackEntry? getCurrentBackStackEntry();
+    method public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> getCurrentBackStackEntryFlow();
+    method public androidx.navigation.NavDestination? getCurrentDestination();
+    method @MainThread public androidx.navigation.NavGraph getGraph();
+    method public androidx.navigation.NavInflater getNavInflater();
+    method public androidx.navigation.NavigatorProvider getNavigatorProvider();
+    method public androidx.navigation.NavBackStackEntry? getPreviousBackStackEntry();
+    method public androidx.lifecycle.ViewModelStoreOwner getViewModelStoreOwner(@IdRes int navGraphId);
+    method public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> getVisibleEntries();
+    method @MainThread public boolean handleDeepLink(android.content.Intent? intent);
+    method @MainThread public void navigate(@IdRes int resId);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(@IdRes int resId, android.os.Bundle? args, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(android.net.Uri deepLink);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(android.net.Uri deepLink, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDeepLinkRequest request, androidx.navigation.NavOptions? navOptions, androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.NavOptions? navOptions);
+    method @MainThread public void navigate(androidx.navigation.NavDirections directions, androidx.navigation.Navigator.Extras navigatorExtras);
+    method @MainThread public final void navigate(String route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavOptionsBuilder,kotlin.Unit> builder);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions, optional androidx.navigation.Navigator.Extras? navigatorExtras);
+    method @MainThread public final void navigate(String route, optional androidx.navigation.NavOptions? navOptions);
+    method @MainThread public final void navigate(String route);
+    method @MainThread public boolean navigateUp();
+    method @MainThread public boolean popBackStack();
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive);
+    method @MainThread public boolean popBackStack(@IdRes int destinationId, boolean inclusive, boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive, optional boolean saveState);
+    method @MainThread public final boolean popBackStack(String route, boolean inclusive);
+    method public void removeOnDestinationChangedListener(androidx.navigation.NavController.OnDestinationChangedListener listener);
+    method @CallSuper public void restoreState(android.os.Bundle? navState);
+    method @CallSuper public android.os.Bundle? saveState();
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId);
+    method @CallSuper @MainThread public void setGraph(@NavigationRes int graphResId, android.os.Bundle? startDestinationArgs);
+    method @CallSuper @MainThread public void setGraph(androidx.navigation.NavGraph graph, android.os.Bundle? startDestinationArgs);
+    property public androidx.navigation.NavBackStackEntry? currentBackStackEntry;
+    property public final kotlinx.coroutines.flow.Flow<androidx.navigation.NavBackStackEntry> currentBackStackEntryFlow;
+    property public androidx.navigation.NavDestination? currentDestination;
+    property @MainThread public androidx.navigation.NavGraph graph;
+    property public androidx.navigation.NavInflater navInflater;
+    property public androidx.navigation.NavigatorProvider navigatorProvider;
+    property public androidx.navigation.NavBackStackEntry? previousBackStackEntry;
+    property public final kotlinx.coroutines.flow.StateFlow<java.util.List<androidx.navigation.NavBackStackEntry>> visibleEntries;
+    field public static final androidx.navigation.NavController.Companion Companion;
+    field public static final String KEY_DEEP_LINK_INTENT = "android-support-nav:controller:deepLinkIntent";
+  }
+
+  public static final class NavController.Companion {
+  }
+
+  public static fun interface NavController.OnDestinationChangedListener {
+    method public void onDestinationChanged(androidx.navigation.NavController controller, androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+  }
+
+  public final class NavControllerKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavController, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavDeepLinkBuilder {
+    ctor public NavDeepLinkBuilder(android.content.Context context);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder addDestination(String route);
+    method public android.app.PendingIntent createPendingIntent();
+    method public androidx.core.app.TaskStackBuilder createTaskStackBuilder();
+    method public androidx.navigation.NavDeepLinkBuilder setArguments(android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(Class<? extends android.app.Activity> activityClass);
+    method public androidx.navigation.NavDeepLinkBuilder setComponentName(android.content.ComponentName componentName);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(@IdRes int destId);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute, optional android.os.Bundle? args);
+    method public androidx.navigation.NavDeepLinkBuilder setDestination(String destRoute);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(@NavigationRes int navGraphId);
+    method public androidx.navigation.NavDeepLinkBuilder setGraph(androidx.navigation.NavGraph navGraph);
+  }
+
+  public interface NavHost {
+    method public androidx.navigation.NavController getNavController();
+    property public abstract androidx.navigation.NavController navController;
+  }
+
+  public class NavHostController extends androidx.navigation.NavController {
+    ctor public NavHostController(android.content.Context context);
+    method public final void enableOnBackPressed(boolean enabled);
+    method public final void setLifecycleOwner(androidx.lifecycle.LifecycleOwner owner);
+    method public final void setOnBackPressedDispatcher(androidx.activity.OnBackPressedDispatcher dispatcher);
+    method public final void setViewModelStore(androidx.lifecycle.ViewModelStore viewModelStore);
+  }
+
+  public final class NavHostKt {
+    method @Deprecated public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, optional @IdRes int id, @IdRes int startDestination, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+    method public static inline androidx.navigation.NavGraph createGraph(androidx.navigation.NavHost, String startDestination, optional String? route, kotlin.jvm.functions.Function1<? super androidx.navigation.NavGraphBuilder,kotlin.Unit> builder);
+  }
+
+  public final class NavInflater {
+    ctor public NavInflater(android.content.Context context, androidx.navigation.NavigatorProvider navigatorProvider);
+    method public androidx.navigation.NavGraph inflate(@NavigationRes int graphResId);
+    field public static final androidx.navigation.NavInflater.Companion Companion;
+  }
+
+  public static final class NavInflater.Companion {
+  }
+
+  public final class Navigation {
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId, optional android.os.Bundle? args);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(@IdRes int resId);
+    method public static android.view.View.OnClickListener createNavigateOnClickListener(androidx.navigation.NavDirections directions);
+    method public static androidx.navigation.NavController findNavController(android.app.Activity activity, @IdRes int viewId);
+    method public static androidx.navigation.NavController findNavController(android.view.View view);
+    method public static void setViewNavController(android.view.View view, androidx.navigation.NavController? controller);
+    field public static final androidx.navigation.Navigation INSTANCE;
+  }
+
+  public final class ViewKt {
+    method public static androidx.navigation.NavController findNavController(android.view.View);
+  }
+
+}
+
diff --git a/navigation/navigation-testing/api/2.6.0-beta01.txt b/navigation/navigation-testing/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..89f60a4
--- /dev/null
+++ b/navigation/navigation-testing/api/2.6.0-beta01.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.navigation.testing {
+
+  public final class TestNavHostController extends androidx.navigation.NavHostController {
+    ctor public TestNavHostController(android.content.Context context);
+    method public java.util.List<androidx.navigation.NavBackStackEntry> getBackStack();
+    method public void setCurrentDestination(@IdRes int destId, optional android.os.Bundle args);
+    method public void setCurrentDestination(@IdRes int destId);
+    method public void setCurrentDestination(String destRoute, optional android.os.Bundle args);
+    method public void setCurrentDestination(String destRoute);
+    property public final java.util.List<androidx.navigation.NavBackStackEntry> backStack;
+  }
+
+  public final class TestNavigatorState extends androidx.navigation.NavigatorState {
+    ctor public TestNavigatorState(optional android.content.Context? context, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+    ctor public TestNavigatorState(optional android.content.Context? context);
+    ctor public TestNavigatorState();
+    method public androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public androidx.navigation.NavBackStackEntry restoreBackStackEntry(androidx.navigation.NavBackStackEntry previouslySavedEntry);
+  }
+
+}
+
diff --git a/navigation/navigation-testing/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-testing/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..89f60a4
--- /dev/null
+++ b/navigation/navigation-testing/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.navigation.testing {
+
+  public final class TestNavHostController extends androidx.navigation.NavHostController {
+    ctor public TestNavHostController(android.content.Context context);
+    method public java.util.List<androidx.navigation.NavBackStackEntry> getBackStack();
+    method public void setCurrentDestination(@IdRes int destId, optional android.os.Bundle args);
+    method public void setCurrentDestination(@IdRes int destId);
+    method public void setCurrentDestination(String destRoute, optional android.os.Bundle args);
+    method public void setCurrentDestination(String destRoute);
+    property public final java.util.List<androidx.navigation.NavBackStackEntry> backStack;
+  }
+
+  public final class TestNavigatorState extends androidx.navigation.NavigatorState {
+    ctor public TestNavigatorState(optional android.content.Context? context, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+    ctor public TestNavigatorState(optional android.content.Context? context);
+    ctor public TestNavigatorState();
+    method public androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public androidx.navigation.NavBackStackEntry restoreBackStackEntry(androidx.navigation.NavBackStackEntry previouslySavedEntry);
+  }
+
+}
+
diff --git a/navigation/navigation-testing/api/res-2.6.0-beta01.txt b/navigation/navigation-testing/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-testing/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-testing/api/restricted_2.6.0-beta01.txt b/navigation/navigation-testing/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..89f60a4
--- /dev/null
+++ b/navigation/navigation-testing/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.navigation.testing {
+
+  public final class TestNavHostController extends androidx.navigation.NavHostController {
+    ctor public TestNavHostController(android.content.Context context);
+    method public java.util.List<androidx.navigation.NavBackStackEntry> getBackStack();
+    method public void setCurrentDestination(@IdRes int destId, optional android.os.Bundle args);
+    method public void setCurrentDestination(@IdRes int destId);
+    method public void setCurrentDestination(String destRoute, optional android.os.Bundle args);
+    method public void setCurrentDestination(String destRoute);
+    property public final java.util.List<androidx.navigation.NavBackStackEntry> backStack;
+  }
+
+  public final class TestNavigatorState extends androidx.navigation.NavigatorState {
+    ctor public TestNavigatorState(optional android.content.Context? context, optional kotlinx.coroutines.CoroutineDispatcher coroutineDispatcher);
+    ctor public TestNavigatorState(optional android.content.Context? context);
+    ctor public TestNavigatorState();
+    method public androidx.navigation.NavBackStackEntry createBackStackEntry(androidx.navigation.NavDestination destination, android.os.Bundle? arguments);
+    method public androidx.navigation.NavBackStackEntry restoreBackStackEntry(androidx.navigation.NavBackStackEntry previouslySavedEntry);
+  }
+
+}
+
diff --git a/navigation/navigation-ui-ktx/api/2.6.0-beta01.txt b/navigation/navigation-ui-ktx/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-ui-ktx/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-ui-ktx/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-ui-ktx/api/res-2.6.0-beta01.txt b/navigation/navigation-ui-ktx/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/res-2.6.0-beta01.txt
diff --git a/navigation/navigation-ui-ktx/api/restricted_2.6.0-beta01.txt b/navigation/navigation-ui-ktx/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/navigation/navigation-ui-ktx/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/navigation/navigation-ui/api/2.6.0-beta01.txt b/navigation/navigation-ui/api/2.6.0-beta01.txt
new file mode 100644
index 0000000..27e99a9
--- /dev/null
+++ b/navigation/navigation-ui/api/2.6.0-beta01.txt
@@ -0,0 +1,88 @@
+// Signature format: 4.0
+package androidx.navigation.ui {
+
+  public final class ActivityKt {
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class AppBarConfiguration {
+    method @Deprecated public androidx.drawerlayout.widget.DrawerLayout? getDrawerLayout();
+    method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+    method public androidx.customview.widget.Openable? getOpenableLayout();
+    method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+    method public boolean isTopLevelDestination(androidx.navigation.NavDestination destination);
+    property @Deprecated public final androidx.drawerlayout.widget.DrawerLayout? drawerLayout;
+    property public final androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener;
+    property public final androidx.customview.widget.Openable? openableLayout;
+    property public final java.util.Set<java.lang.Integer> topLevelDestinations;
+  }
+
+  public static final class AppBarConfiguration.Builder {
+    ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph navGraph);
+    ctor public AppBarConfiguration.Builder(android.view.Menu topLevelMenu);
+    ctor public AppBarConfiguration.Builder(int... topLevelDestinationIds);
+    ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer> topLevelDestinationIds);
+    method public androidx.navigation.ui.AppBarConfiguration build();
+    method @Deprecated public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setOpenableLayout(androidx.customview.widget.Openable? openableLayout);
+  }
+
+  public static fun interface AppBarConfiguration.OnNavigateUpListener {
+    method public boolean onNavigateUp();
+  }
+
+  public final class AppBarConfigurationKt {
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+  }
+
+  public final class BottomNavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView, androidx.navigation.NavController navController);
+  }
+
+  public final class CollapsingToolbarLayoutKt {
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class MenuItemKt {
+    method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+  }
+
+  public final class NavControllerKt {
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.customview.widget.Openable? drawerLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+  }
+
+  public final class NavigationUI {
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController);
+    field public static final androidx.navigation.ui.NavigationUI INSTANCE;
+  }
+
+  public final class NavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView, androidx.navigation.NavController navController);
+  }
+
+  public final class ToolbarKt {
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+}
+
diff --git a/navigation/navigation-ui/api/public_plus_experimental_2.6.0-beta01.txt b/navigation/navigation-ui/api/public_plus_experimental_2.6.0-beta01.txt
new file mode 100644
index 0000000..7cb97e2
--- /dev/null
+++ b/navigation/navigation-ui/api/public_plus_experimental_2.6.0-beta01.txt
@@ -0,0 +1,94 @@
+// Signature format: 4.0
+package androidx.navigation.ui {
+
+  public final class ActivityKt {
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class AppBarConfiguration {
+    method @Deprecated public androidx.drawerlayout.widget.DrawerLayout? getDrawerLayout();
+    method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+    method public androidx.customview.widget.Openable? getOpenableLayout();
+    method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+    method public boolean isTopLevelDestination(androidx.navigation.NavDestination destination);
+    property @Deprecated public final androidx.drawerlayout.widget.DrawerLayout? drawerLayout;
+    property public final androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener;
+    property public final androidx.customview.widget.Openable? openableLayout;
+    property public final java.util.Set<java.lang.Integer> topLevelDestinations;
+  }
+
+  public static final class AppBarConfiguration.Builder {
+    ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph navGraph);
+    ctor public AppBarConfiguration.Builder(android.view.Menu topLevelMenu);
+    ctor public AppBarConfiguration.Builder(int... topLevelDestinationIds);
+    ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer> topLevelDestinationIds);
+    method public androidx.navigation.ui.AppBarConfiguration build();
+    method @Deprecated public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setOpenableLayout(androidx.customview.widget.Openable? openableLayout);
+  }
+
+  public static fun interface AppBarConfiguration.OnNavigateUpListener {
+    method public boolean onNavigateUp();
+  }
+
+  public final class AppBarConfigurationKt {
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+  }
+
+  public final class BottomNavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView, androidx.navigation.NavController navController);
+  }
+
+  public final class CollapsingToolbarLayoutKt {
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class MenuItemKt {
+    method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+  }
+
+  public final class NavControllerKt {
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.customview.widget.Openable? drawerLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+  }
+
+  public final class NavigationUI {
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController);
+    method @androidx.navigation.ui.NavigationUiSaveStateControl public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController, boolean saveState);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController);
+    method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController, boolean saveState);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController);
+    method @androidx.navigation.ui.NavigationUiSaveStateControl public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController, boolean saveState);
+    field public static final androidx.navigation.ui.NavigationUI INSTANCE;
+  }
+
+  @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface NavigationUiSaveStateControl {
+  }
+
+  public final class NavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView, androidx.navigation.NavController navController);
+  }
+
+  public final class ToolbarKt {
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+}
+
diff --git a/navigation/navigation-ui/api/res-2.6.0-beta01.txt b/navigation/navigation-ui/api/res-2.6.0-beta01.txt
new file mode 100644
index 0000000..e65fdbe
--- /dev/null
+++ b/navigation/navigation-ui/api/res-2.6.0-beta01.txt
@@ -0,0 +1,8 @@
+anim nav_default_enter_anim
+anim nav_default_exit_anim
+anim nav_default_pop_enter_anim
+anim nav_default_pop_exit_anim
+animator nav_default_enter_anim
+animator nav_default_exit_anim
+animator nav_default_pop_enter_anim
+animator nav_default_pop_exit_anim
diff --git a/navigation/navigation-ui/api/restricted_2.6.0-beta01.txt b/navigation/navigation-ui/api/restricted_2.6.0-beta01.txt
new file mode 100644
index 0000000..27e99a9
--- /dev/null
+++ b/navigation/navigation-ui/api/restricted_2.6.0-beta01.txt
@@ -0,0 +1,88 @@
+// Signature format: 4.0
+package androidx.navigation.ui {
+
+  public final class ActivityKt {
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class AppBarConfiguration {
+    method @Deprecated public androidx.drawerlayout.widget.DrawerLayout? getDrawerLayout();
+    method public androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? getFallbackOnNavigateUpListener();
+    method public androidx.customview.widget.Openable? getOpenableLayout();
+    method public java.util.Set<java.lang.Integer> getTopLevelDestinations();
+    method public boolean isTopLevelDestination(androidx.navigation.NavDestination destination);
+    property @Deprecated public final androidx.drawerlayout.widget.DrawerLayout? drawerLayout;
+    property public final androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener;
+    property public final androidx.customview.widget.Openable? openableLayout;
+    property public final java.util.Set<java.lang.Integer> topLevelDestinations;
+  }
+
+  public static final class AppBarConfiguration.Builder {
+    ctor public AppBarConfiguration.Builder(androidx.navigation.NavGraph navGraph);
+    ctor public AppBarConfiguration.Builder(android.view.Menu topLevelMenu);
+    ctor public AppBarConfiguration.Builder(int... topLevelDestinationIds);
+    ctor public AppBarConfiguration.Builder(java.util.Set<java.lang.Integer> topLevelDestinationIds);
+    method public androidx.navigation.ui.AppBarConfiguration build();
+    method @Deprecated public androidx.navigation.ui.AppBarConfiguration.Builder setDrawerLayout(androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setFallbackOnNavigateUpListener(androidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener? fallbackOnNavigateUpListener);
+    method public androidx.navigation.ui.AppBarConfiguration.Builder setOpenableLayout(androidx.customview.widget.Openable? openableLayout);
+  }
+
+  public static fun interface AppBarConfiguration.OnNavigateUpListener {
+    method public boolean onNavigateUp();
+  }
+
+  public final class AppBarConfigurationKt {
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(androidx.navigation.NavGraph navGraph, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(android.view.Menu topLevelMenu, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+    method public static inline androidx.navigation.ui.AppBarConfiguration AppBarConfiguration(java.util.Set<java.lang.Integer> topLevelDestinationIds, optional androidx.customview.widget.Openable? drawerLayout, optional kotlin.jvm.functions.Function0<java.lang.Boolean> fallbackOnNavigateUpListener);
+  }
+
+  public final class BottomNavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView, androidx.navigation.NavController navController);
+  }
+
+  public final class CollapsingToolbarLayoutKt {
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+  public final class MenuItemKt {
+    method public static boolean onNavDestinationSelected(android.view.MenuItem, androidx.navigation.NavController navController);
+  }
+
+  public final class NavControllerKt {
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.customview.widget.Openable? drawerLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController, androidx.navigation.ui.AppBarConfiguration appBarConfiguration);
+  }
+
+  public final class NavigationUI {
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static boolean navigateUp(androidx.navigation.NavController navController, androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static boolean onNavDestinationSelected(android.view.MenuItem item, androidx.navigation.NavController navController);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupActionBarWithNavController(androidx.appcompat.app.AppCompatActivity activity, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, androidx.customview.widget.Openable? openableLayout);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+    method public static void setupWithNavController(com.google.android.material.appbar.CollapsingToolbarLayout collapsingToolbarLayout, androidx.appcompat.widget.Toolbar toolbar, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView navigationView, androidx.navigation.NavController navController);
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationBarView navigationBarView, androidx.navigation.NavController navController);
+    field public static final androidx.navigation.ui.NavigationUI INSTANCE;
+  }
+
+  public final class NavigationViewKt {
+    method public static void setupWithNavController(com.google.android.material.navigation.NavigationView, androidx.navigation.NavController navController);
+  }
+
+  public final class ToolbarKt {
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, androidx.drawerlayout.widget.DrawerLayout? drawerLayout);
+    method public static void setupWithNavController(androidx.appcompat.widget.Toolbar, androidx.navigation.NavController navController, optional androidx.navigation.ui.AppBarConfiguration configuration);
+  }
+
+}
+
diff --git a/paging/paging-compose/api/current.txt b/paging/paging-compose/api/current.txt
index da8a532..79638bd 100644
--- a/paging/paging-compose/api/current.txt
+++ b/paging/paging-compose/api/current.txt
@@ -21,8 +21,8 @@
 
   public final class LazyPagingItemsKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
-    method public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
-    method public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
 }
diff --git a/paging/paging-compose/api/public_plus_experimental_current.txt b/paging/paging-compose/api/public_plus_experimental_current.txt
index da8a532..79638bd 100644
--- a/paging/paging-compose/api/public_plus_experimental_current.txt
+++ b/paging/paging-compose/api/public_plus_experimental_current.txt
@@ -21,8 +21,8 @@
 
   public final class LazyPagingItemsKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
-    method public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
-    method public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
 }
diff --git a/paging/paging-compose/api/restricted_current.txt b/paging/paging-compose/api/restricted_current.txt
index da8a532..79638bd 100644
--- a/paging/paging-compose/api/restricted_current.txt
+++ b/paging/paging-compose/api/restricted_current.txt
@@ -21,8 +21,8 @@
 
   public final class LazyPagingItemsKt {
     method @androidx.compose.runtime.Composable public static <T> androidx.paging.compose.LazyPagingItems<T> collectAsLazyPagingItems(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<T>>, optional kotlin.coroutines.CoroutineContext context);
-    method public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
-    method public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void items(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function1<? super T,?>? key, optional kotlin.jvm.functions.Function1<? super T,?>? contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.LazyItemScope,? super T,kotlin.Unit> itemContent);
+    method @Deprecated public static <T> void itemsIndexed(androidx.compose.foundation.lazy.LazyListScope, androidx.paging.compose.LazyPagingItems<T> items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.LazyItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
 }
diff --git a/paging/paging-compose/build.gradle b/paging/paging-compose/build.gradle
index 80ba12e..918280d 100644
--- a/paging/paging-compose/build.gradle
+++ b/paging/paging-compose/build.gradle
@@ -37,7 +37,6 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.truth)
-    androidTestImplementation(project(":internal-testutils-ktx"))
 
     samples(projectOrArtifact(":paging:paging-compose:paging-compose-samples"))
 }
diff --git a/paging/paging-compose/integration-tests/paging-demos/src/main/java/androidx/paging/compose/demos/room/PagingRoomSample.kt b/paging/paging-compose/integration-tests/paging-demos/src/main/java/androidx/paging/compose/demos/room/PagingRoomSample.kt
index 27ebfb1..e16c7b7 100644
--- a/paging/paging-compose/integration-tests/paging-demos/src/main/java/androidx/paging/compose/demos/room/PagingRoomSample.kt
+++ b/paging/paging-compose/integration-tests/paging-demos/src/main/java/androidx/paging/compose/demos/room/PagingRoomSample.kt
@@ -34,7 +34,7 @@
 import androidx.paging.Pager
 import androidx.paging.PagingConfig
 import androidx.paging.compose.collectAsLazyPagingItems
-import androidx.paging.compose.itemsIndexed
+import androidx.paging.compose.itemKey
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlin.random.Random
@@ -113,10 +113,11 @@
 
         val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
         LazyColumn {
-            itemsIndexed(
-                items = lazyPagingItems,
-                key = { _, user -> user.id }
-            ) { index, user ->
+            items(
+                count = lazyPagingItems.itemCount,
+                key = lazyPagingItems.itemKey { user -> user.id },
+            ) { index ->
+                val user = lazyPagingItems[index]
                 var counter by rememberSaveable { mutableStateOf(0) }
                 Text(
                     text = "counter=$counter index=$index ${user?.name} ${user?.id}",
diff --git a/paging/paging-compose/samples/build.gradle b/paging/paging-compose/samples/build.gradle
index 68a2247..146fee1 100644
--- a/paging/paging-compose/samples/build.gradle
+++ b/paging/paging-compose/samples/build.gradle
@@ -27,9 +27,9 @@
     implementation(libs.kotlinStdlib)
 
     compileOnly(projectOrArtifact(":annotation:annotation-sampled"))
-    implementation(project(":compose:foundation:foundation"))
-    implementation(project(":compose:material:material"))
-    implementation(projectOrArtifact(":paging:paging-compose"))
+    implementation(projectOrArtifact(":compose:foundation:foundation"))
+    implementation(projectOrArtifact(":compose:material:material"))
+    implementation(project(":paging:paging-compose"))
     implementation(project(":internal-testutils-paging"))
 }
 
diff --git a/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt b/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
index aec33e1..f301c44 100644
--- a/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
+++ b/paging/paging-compose/samples/src/main/java/androidx/paging/compose/samples/PagingSample.kt
@@ -34,8 +34,7 @@
 import androidx.paging.PagingSource
 import androidx.paging.PagingState
 import androidx.paging.compose.collectAsLazyPagingItems
-import androidx.paging.compose.items
-import androidx.paging.compose.itemsIndexed
+import androidx.paging.compose.itemKey
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlin.math.ceil
@@ -129,7 +128,8 @@
             }
         }
 
-        itemsIndexed(lazyPagingItems) { index, item ->
+        items(count = lazyPagingItems.itemCount) { index ->
+            val item = lazyPagingItems[index]
             Text("Index=$index: $item", fontSize = 20.sp)
         }
 
@@ -149,8 +149,12 @@
 fun ItemsDemo(flow: Flow<PagingData<String>>) {
     val lazyPagingItems = flow.collectAsLazyPagingItems()
     LazyColumn {
-        items(lazyPagingItems) {
-            Text("Item is $it")
+        items(
+            count = lazyPagingItems.itemCount,
+            key = lazyPagingItems.itemKey()
+        ) { index ->
+            val item = lazyPagingItems[index]
+            Text("Item is $item")
         }
     }
 }
@@ -160,7 +164,8 @@
 fun ItemsIndexedDemo(flow: Flow<PagingData<String>>) {
     val lazyPagingItems = flow.collectAsLazyPagingItems()
     LazyColumn {
-        itemsIndexed(lazyPagingItems) { index, item ->
+        items(count = lazyPagingItems.itemCount) { index ->
+            val item = lazyPagingItems[index]
             Text("Item at index $index is $item")
         }
     }
diff --git a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
index 1e59f5a..50470e1 100644
--- a/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
+++ b/paging/paging-compose/src/androidTest/java/androidx/paging/compose/LazyPagingItemsTest.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
-import androidx.testutils.TestDispatcher
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
@@ -48,12 +47,15 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
 import org.junit.Assert.assertFalse
 import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 class LazyPagingItemsTest {
@@ -72,8 +74,9 @@
             initialLoadSize = 3,
             prefetchDistance = 1,
         ),
+        loadDelay: Long = 0,
         pagingSourceFactory: () -> PagingSource<Int, Int> = {
-            TestPagingSource(items = items, loadDelay = 0)
+            TestPagingSource(items = items, loadDelay = loadDelay)
         }
     ): Pager<Int, Int> {
         return Pager(config = config, pagingSourceFactory = pagingSourceFactory)
@@ -118,10 +121,10 @@
         assertThat(loadStates.first()).isEqualTo(expected)
     }
 
-    @Ignore // b/267374463
     @Test
     fun lazyPagingLoadStateAfterRefresh() {
-        val pager = createPager()
+        val pager = createPager(loadDelay = 100)
+
         val loadStates: MutableList<CombinedLoadStates> = mutableListOf()
 
         lateinit var lazyPagingItems: LazyPagingItems<Int>
@@ -130,10 +133,23 @@
             loadStates.add(lazyPagingItems.loadState)
         }
 
-        // we only want loadStates after manual refresh
-        loadStates.clear()
-        lazyPagingItems.refresh()
-        rule.waitForIdle()
+        // wait for both compose and paging to complete
+        rule.waitUntil {
+            rule.waitForIdle()
+            lazyPagingItems.loadState.refresh == LoadState.NotLoading(false)
+        }
+
+        rule.runOnIdle {
+            // we only want loadStates after manual refresh
+            loadStates.clear()
+            lazyPagingItems.refresh()
+        }
+
+        // wait for both compose and paging to complete
+        rule.waitUntil {
+            rule.waitForIdle()
+            lazyPagingItems.loadState.refresh == LoadState.NotLoading(false)
+        }
 
         assertThat(loadStates).isNotEmpty()
         val expected = CombinedLoadStates(
@@ -156,8 +172,9 @@
         rule.setContent {
             val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyColumn(Modifier.height(200.dp)) {
-                items(lazyPagingItems) {
-                    Spacer(Modifier.height(101.dp).fillParentMaxWidth().testTag("$it"))
+                items(count = lazyPagingItems.itemCount) { index ->
+                    val item = lazyPagingItems[index]
+                    Spacer(Modifier.height(101.dp).fillParentMaxWidth().testTag("$item"))
                 }
             }
         }
@@ -177,6 +194,7 @@
             .assertDoesNotExist()
     }
 
+    @Suppress("DEPRECATION")
     @Test
     fun lazyPagingColumnShowsIndexedItems() {
         val pager = createPager()
@@ -213,8 +231,9 @@
         rule.setContent {
             val lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyRow(Modifier.width(200.dp)) {
-                items(lazyPagingItems) {
-                    Spacer(Modifier.width(101.dp).fillParentMaxHeight().testTag("$it"))
+                items(count = lazyPagingItems.itemCount) { index ->
+                    val item = lazyPagingItems[index]
+                    Spacer(Modifier.width(101.dp).fillParentMaxHeight().testTag("$item"))
                 }
             }
         }
@@ -234,6 +253,7 @@
             .assertDoesNotExist()
     }
 
+    @Suppress("DEPRECATION")
     @Test
     fun lazyPagingRowShowsIndexedItems() {
         val pager = createPager()
@@ -286,10 +306,13 @@
                     Content("0")
                 }
                 items(
-                    items = lazyPagingItems,
-                    contentType = { if (it == 8) "reuse" else "not-to-reuse-$it" }
-                ) {
-                    Content("$it")
+                    count = lazyPagingItems.itemCount,
+                    contentType = lazyPagingItems.itemContentType(
+                        contentType = { if (it == 8) "reuse" else "not-to-reuse-$it" }
+                    )
+                ) { index ->
+                    val item = lazyPagingItems[index]
+                    Content("$item")
                 }
             }
         }
@@ -355,11 +378,14 @@
                     Content("0")
                 }
                 items(
-                    items = lazyPagingItems,
+                    count = lazyPagingItems.itemCount,
                     // item 7 would be null, which should default to PagingPlaceholderContentType
-                    contentType = { "not-to-reuse-$it" }
-                ) {
-                    Content("$it")
+                    contentType = lazyPagingItems.itemContentType(
+                        contentType = { "not-to-reuse-$it" }
+                    )
+                ) { index ->
+                    val item = lazyPagingItems[index]
+                    Content("$item")
                 }
             }
         }
@@ -419,11 +445,12 @@
                     Content("0")
                 }
                 items(
-                    items = lazyPagingItems,
+                    count = lazyPagingItems.itemCount,
                     // should default to null
-                    contentType = null
-                ) {
-                    Content("$it")
+                    contentType = lazyPagingItems.itemContentType(null)
+                ) { index ->
+                    val item = lazyPagingItems[index]
+                    Content("$item")
                 }
             }
         }
@@ -670,8 +697,9 @@
         rule.setContent {
             lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyColumn(Modifier.height(itemSize * 3)) {
-                items(lazyPagingItems) {
-                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$it"))
+                items(count = lazyPagingItems.itemCount) { index ->
+                    val item = lazyPagingItems[index]
+                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$item"))
                 }
             }
         }
@@ -716,8 +744,9 @@
         rule.setContent {
             lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyColumn(Modifier.height(itemSize * 3)) {
-                items(lazyPagingItems) {
-                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$it"))
+                items(count = lazyPagingItems.itemCount) { index ->
+                    val item = lazyPagingItems[index]
+                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$item"))
                 }
             }
         }
@@ -760,8 +789,9 @@
         rule.setContent {
             lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyColumn(Modifier.height(itemSize * 3)) {
-                items(lazyPagingItems) {
-                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$it"))
+                items(count = lazyPagingItems.itemCount) { index ->
+                    val item = lazyPagingItems[index]
+                    Spacer(Modifier.height(itemSize).fillParentMaxWidth().testTag("$item"))
                 }
             }
         }
@@ -794,9 +824,13 @@
         rule.setContent {
             lazyPagingItems = pager.flow.collectAsLazyPagingItems()
             LazyColumn {
-                items(lazyPagingItems, key = { it }) {
+                items(
+                    count = lazyPagingItems.itemCount,
+                    key = lazyPagingItems.itemKey { it },
+                ) { index ->
+                    val item = lazyPagingItems[index]
                     BasicText(
-                        "Item=$it. counter=${remember { counter++ }}"
+                        "Item=$item. counter=${remember { counter++ }}"
                     )
                 }
             }
@@ -815,6 +849,7 @@
             .assertExists()
     }
 
+    @Suppress("DEPRECATION")
     @Test
     fun stateIsMovedWithItemWithCustomKey_itemsIndexed() {
         val items = mutableListOf(1)
@@ -874,10 +909,9 @@
             TestPagingSource(items = items, loadDelay = 0)
         }
 
-        val context = TestDispatcher()
+        val context = StandardTestDispatcher()
         lateinit var lazyPagingItems: LazyPagingItems<Int>
         rule.setContent {
-            assertThat(context.queue).isEmpty()
             lazyPagingItems = pager.flow.collectAsLazyPagingItems(context)
         }
 
@@ -888,11 +922,11 @@
         }
 
         // start LaunchedEffects
-        context.executeAll()
+        context.scheduler.advanceUntilIdle()
 
         rule.runOnIdle {
             // continue with pagingDataDiffer collections
-            context.executeAll()
+            context.scheduler.advanceUntilIdle()
         }
         rule.waitUntil {
             lazyPagingItems.itemCount == items.size
diff --git a/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt b/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
index 2614263..ee5a63b 100644
--- a/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
+++ b/paging/paging-compose/src/main/java/androidx/paging/compose/LazyPagingItems.kt
@@ -48,8 +48,8 @@
  * The class responsible for accessing the data from a [Flow] of [PagingData].
  * In order to obtain an instance of [LazyPagingItems] use the [collectAsLazyPagingItems] extension
  * method of [Flow] with [PagingData].
- * This instance can be used by the [items] and [itemsIndexed] methods inside [LazyListScope] to
- * display data received from the [Flow] of [PagingData].
+ * This instance can be used for Lazy foundations such as [LazyListScope.items] to display data
+ * received from the [Flow] of [PagingData].
  *
  * @param T the type of value used by [PagingData].
  */
@@ -240,8 +240,8 @@
 
 /**
  * Collects values from this [Flow] of [PagingData] and represents them inside a [LazyPagingItems]
- * instance. The [LazyPagingItems] instance can be used by the [items] and [itemsIndexed] methods
- * from [LazyListScope] in order to display the data obtained from a [Flow] of [PagingData].
+ * instance. The [LazyPagingItems] instance can be used for lazy foundations such as
+ * [LazyListScope.items] in order to display the data obtained from a [Flow] of [PagingData].
  *
  * @sample androidx.paging.compose.samples.PagingBackendSample
  *
@@ -298,7 +298,26 @@
  * @param itemContent the content displayed by a single item. In case the item is `null`, the
  * [itemContent] method should handle the logic of displaying a placeholder instead of the main
  * content displayed by an item which is not `null`.
+ *
+ * @deprecated Call [LazyListScope.items] directly with LazyPagingItems [itemKey] and
+ * [itemContentType] helper functions.
  */
+@Deprecated(
+    message = "Call LazyListScope.items directly with LazyPagingItems #itemKey and" +
+        "#itemContentType helper functions.",
+    replaceWith = ReplaceWith(
+        expression = """items(
+           count = items.itemCount,
+           key = items.itemKey(key),
+           contentType = items.itemContentType(
+                contentType
+           )
+        ) { index ->
+            val item = items[index]
+            itemContent(item)
+        }""",
+    )
+)
 public fun <T : Any> LazyListScope.items(
     items: LazyPagingItems<T>,
     key: ((item: T) -> Any)? = null,
@@ -335,7 +354,28 @@
  * @param itemContent the content displayed by a single item. In case the item is `null`, the
  * [itemContent] method should handle the logic of displaying a placeholder instead of the main
  * content displayed by an item which is not `null`.
+ *
+ * @deprecated Deprecating support for indexed keys on non-null items as it is susceptible to
+ * errors when items indices shift due to prepends. Call LazyListScope.items directly
+ * with LazyPagingItems #itemKey and #itemContentType helper functions.
  */
+@Deprecated(
+    message = "Deprecating support for indexed keys on non-null items as it is susceptible to" +
+        "errors when items indices shift due to prepends. Call LazyListScope.items directly" +
+        "with LazyPagingItems #itemKey and #itemContentType helper functions.",
+    replaceWith = ReplaceWith(
+        expression = """items(
+           count = items.itemCount,
+           key = items.itemKey(key),
+           contentType = items.itemContentType(
+                contentType
+           )
+        ) { index ->
+            val item = items[index]
+            itemContent(item)
+        }""",
+    )
+)
 public fun <T : Any> LazyListScope.itemsIndexed(
     items: LazyPagingItems<T>,
     key: ((index: Int, item: T) -> Any)? = null,
diff --git a/paging/paging-testing/api/current.txt b/paging/paging-testing/api/current.txt
index f59510c..066939a 100644
--- a/paging/paging-testing/api/current.txt
+++ b/paging/paging-testing/api/current.txt
@@ -14,7 +14,7 @@
   }
 
   public final class PagerFlowSnapshotKt {
-    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, kotlin.coroutines.Continuation<java.util.List<Value>>);
+    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
   }
 
   public final class SnapshotLoader<Value> {
diff --git a/paging/paging-testing/api/public_plus_experimental_current.txt b/paging/paging-testing/api/public_plus_experimental_current.txt
index f59510c..066939a 100644
--- a/paging/paging-testing/api/public_plus_experimental_current.txt
+++ b/paging/paging-testing/api/public_plus_experimental_current.txt
@@ -14,7 +14,7 @@
   }
 
   public final class PagerFlowSnapshotKt {
-    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, kotlin.coroutines.Continuation<java.util.List<Value>>);
+    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
   }
 
   public final class SnapshotLoader<Value> {
diff --git a/paging/paging-testing/api/restricted_current.txt b/paging/paging-testing/api/restricted_current.txt
index f59510c..066939a 100644
--- a/paging/paging-testing/api/restricted_current.txt
+++ b/paging/paging-testing/api/restricted_current.txt
@@ -14,7 +14,7 @@
   }
 
   public final class PagerFlowSnapshotKt {
-    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, kotlin.coroutines.Continuation<java.util.List<Value>>);
+    method public static suspend <Value> Object? asSnapshot(kotlinx.coroutines.flow.Flow<androidx.paging.PagingData<Value>>, kotlinx.coroutines.CoroutineScope coroutineScope, optional androidx.paging.testing.LoadErrorHandler onError, optional kotlin.jvm.functions.Function2<? super androidx.paging.testing.SnapshotLoader<Value>,? super kotlin.coroutines.Continuation<kotlin.Unit>,?> loadOperations, optional kotlin.coroutines.Continuation<java.util.List<Value>>);
   }
 
   public final class SnapshotLoader<Value> {
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
index cc18526..64c8ece 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/PagerFlowSnapshot.kt
@@ -57,7 +57,7 @@
 public suspend fun <Value : Any> Flow<PagingData<Value>>.asSnapshot(
     coroutineScope: CoroutineScope,
     onError: LoadErrorHandler = LoadErrorHandler { THROW },
-    loadOperations: suspend SnapshotLoader<Value>.() -> @JvmSuppressWildcards Unit
+    loadOperations: suspend SnapshotLoader<Value>.() -> @JvmSuppressWildcards Unit = { }
 ): @JvmSuppressWildcards List<Value> {
 
     lateinit var loader: SnapshotLoader<Value>
diff --git a/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt b/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
index b652e13..e44216e 100644
--- a/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
+++ b/paging/paging-testing/src/main/java/androidx/paging/testing/StaticListPagingSourceFactory.kt
@@ -24,17 +24,19 @@
 import kotlinx.coroutines.launch
 
 /**
- * Extension method on a [Flow] to generate a `PagingSourceFactory` for constructing a [Pager].
+ * Returns a factory that creates [PagingSource] instances.
  *
- * The [Flow] of list represents the data source, with each static list representing a generation
- * of data from which a [PagingSource] will load from. With every emission, the current
- * [PagingSource] will be invalidated, thereby triggering a new generation of Paged data. The
- * same factory should be reused within the lifetime of a ViewModel.
+ * Since this method returns a lambda, call [this.invoke] to create a new PagingSource. Can be
+ * used as the pagingSourceFactory when constructing a [Pager]. The same factory should be reused
+ * within the lifetime of a ViewModel.
+ *
+ * Extension method on a [Flow] of list that represents the data source, with each static list
+ * representing a generation of data from which a [PagingSource] will load from. With every
+ * emission, the current [PagingSource] will be invalidated, thereby triggering a new generation
+ * of Paged data.
  *
  * Supports multiple factories and thus multiple collection on the same flow.
  *
- * Returns a `pagingSourceFactory` to be supplied to a [Pager].
- *
  * @param coroutineScope the CoroutineScope to collect from the Flow of list.
  */
 public fun <Value : Any> Flow<@JvmSuppressWildcards List<Value>>.asPagingSourceFactory(
diff --git a/paging/paging-testing/src/test/kotlin/androidx/paging/testing/PagerFlowSnapshotTest.kt b/paging/paging-testing/src/test/kotlin/androidx/paging/testing/PagerFlowSnapshotTest.kt
index d04d7f9..42aaa0b5 100644
--- a/paging/paging-testing/src/test/kotlin/androidx/paging/testing/PagerFlowSnapshotTest.kt
+++ b/paging/paging-testing/src/test/kotlin/androidx/paging/testing/PagerFlowSnapshotTest.kt
@@ -81,6 +81,19 @@
     }
 
     @Test
+    fun initialRefresh_emptyOperations() {
+        val dataFlow = flowOf(List(30) { it })
+        val pager = createPager(dataFlow)
+        testScope.runTest {
+            val snapshot = pager.asSnapshot(this)
+            // first page + prefetched page
+            assertThat(snapshot).containsExactlyElementsIn(
+                listOf(0, 1, 2, 3, 4, 5, 6, 7)
+            )
+        }
+    }
+
+    @Test
     fun initialRefresh_withSeparators() {
         val dataFlow = flowOf(List(30) { it })
         val pager = createPager(dataFlow).map { pagingData ->
@@ -150,6 +163,19 @@
     }
 
     @Test
+    fun emptyInitialRefresh_emptyOperations() {
+        val dataFlow = emptyFlow<List<Int>>()
+        val pager = createPager(dataFlow)
+        testScope.runTest {
+            val snapshot = pager.asSnapshot(this)
+
+            assertThat(snapshot).containsExactlyElementsIn(
+                emptyList<Int>()
+            )
+        }
+    }
+
+    @Test
     fun manualRefresh() {
         val dataFlow = flowOf(List(30) { it })
         val pager = createPagerNoPrefetch(dataFlow).cachedIn(testScope.backgroundScope)
@@ -651,21 +677,21 @@
         }
         val pager = createPagerNoPrefetch(dataFlow).cachedIn(testScope.backgroundScope)
         testScope.runTest {
-            val snapshot1 = pager.asSnapshot(this) { }
+            val snapshot1 = pager.asSnapshot(this)
             assertThat(snapshot1).containsExactlyElementsIn(
                 emptyList<Int>()
             )
 
             delay(500)
 
-            val snapshot2 = pager.asSnapshot(this) { }
+            val snapshot2 = pager.asSnapshot(this)
             assertThat(snapshot2).containsExactlyElementsIn(
                 listOf(0, 1, 2, 3, 4)
             )
 
             delay(500)
 
-            val snapshot3 = pager.asSnapshot(this) { }
+            val snapshot3 = pager.asSnapshot(this)
             assertThat(snapshot3).containsExactlyElementsIn(
                 listOf(30, 31, 32, 33, 34)
             )
@@ -677,7 +703,7 @@
         val dataFlow = MutableSharedFlow<List<Int>>()
         val pager = createPagerNoPrefetch(dataFlow).cachedIn(testScope.backgroundScope)
         testScope.runTest {
-            val snapshot1 = pager.asSnapshot(this) { }
+            val snapshot1 = pager.asSnapshot(this)
             assertThat(snapshot1).containsExactlyElementsIn(
                 emptyList<Int>()
             )
@@ -704,19 +730,19 @@
         val pager = createPagerNoPrefetch(dataFlow).cachedIn(testScope.backgroundScope)
         testScope.runTest {
             dataFlow.emit(emptyList())
-            val snapshot1 = pager.asSnapshot(this) { }
+            val snapshot1 = pager.asSnapshot(this)
             assertThat(snapshot1).containsExactlyElementsIn(
                 emptyList<Int>()
             )
 
             dataFlow.emit(List(30) { it })
-            val snapshot2 = pager.asSnapshot(this) { }
+            val snapshot2 = pager.asSnapshot(this)
             assertThat(snapshot2).containsExactlyElementsIn(
                 listOf(0, 1, 2, 3, 4)
             )
 
             dataFlow.emit(List(30) { it + 30 })
-            val snapshot3 = pager.asSnapshot(this) { }
+            val snapshot3 = pager.asSnapshot(this)
             assertThat(snapshot3).containsExactlyElementsIn(
                 listOf(30, 31, 32, 33, 34)
             )
@@ -747,7 +773,7 @@
             )
 
             delay(1000)
-            val snapshot2 = pager.asSnapshot(this) { }
+            val snapshot2 = pager.asSnapshot(this)
             // anchorPos = 5, refreshKey = 3
             assertThat(snapshot2).containsExactlyElementsIn(
                 listOf(3, 4, 5, 6, 7)
@@ -768,13 +794,13 @@
         }
         val pager = createPagerNoPrefetch(dataFlow, 10).cachedIn(testScope.backgroundScope)
         testScope.runTest {
-            val snapshot1 = pager.asSnapshot(this) { }
+            val snapshot1 = pager.asSnapshot(this)
             assertThat(snapshot1).containsExactlyElementsIn(
                 listOf(10, 11, 12, 13, 14)
             )
 
             delay(500)
-            val snapshot2 = pager.asSnapshot(this) { }
+            val snapshot2 = pager.asSnapshot(this)
             assertThat(snapshot2).containsExactlyElementsIn(
                 listOf(0, 1, 2, 3, 4)
             )
@@ -805,7 +831,7 @@
             )
 
             delay(1000)
-            val snapshot2 = pager.asSnapshot(this) { }
+            val snapshot2 = pager.asSnapshot(this)
             // anchorPos = 15, refreshKey = 13
             assertThat(snapshot2).containsExactlyElementsIn(
                 listOf(13, 14, 15, 16, 17)
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 903113f..476ad28 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -25,6 +25,6 @@
 kotlin.code.style=official
 # Disable docs
 androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=9848933
-androidx.playground.metalavaBuildId=9753996
+androidx.playground.snapshotBuildId=9912543
+androidx.playground.metalavaBuildId=9883460
 androidx.studio.type=playground
diff --git a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
index e8db299..eaf2d0a 100644
--- a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
+++ b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
@@ -77,7 +77,7 @@
 
             // Add additional dependencies required for KSP outputs
 
-            val toolsVersion = "1.0.0-alpha02"
+            val toolsVersion = "1.0.0-alpha03"
             project.dependencies {
                 add(
                     "ksp",
diff --git a/privacysandbox/tools/tools-apicompiler/build.gradle b/privacysandbox/tools/tools-apicompiler/build.gradle
index ce65d8c..6abb2a1 100644
--- a/privacysandbox/tools/tools-apicompiler/build.gradle
+++ b/privacysandbox/tools/tools-apicompiler/build.gradle
@@ -45,20 +45,24 @@
             dir: "${SdkHelperKt.getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
             include: "android.jar"
     ))
-    // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
-    def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.BUILD_TOOLS_VERSION}/aidl"
-    def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
-    test {
-        inputs.files(aidlCompilerPath)
-                .withPropertyName("aidl_compiler_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        inputs.files(frameworkAidlPath)
-                .withPropertyName("framework_aidl_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        doFirst {
-            systemProperty "aidl_compiler_path", aidlCompilerPath
-            systemProperty "framework_aidl_path", frameworkAidlPath
-        }
+}
+
+// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
+def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.buildToolsVersion(project)}/aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
+def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
+test {
+    inputs.files(aidlCompilerPath)
+            .withPropertyName("aidl_compiler_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.files(frameworkAidlPath)
+            .withPropertyName("framework_aidl_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.dir("src/test/test-data").withPathSensitivity(PathSensitivity.RELATIVE)
+    doFirst {
+        systemProperty "aidl_compiler_path", aidlCompilerPath
+        systemProperty "framework_aidl_path", frameworkAidlPath
+        systemProperty "test_output_dir", testGeneratedSourcesPath
     }
 }
 
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/AbstractApiCompilerDiffTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/AbstractApiCompilerDiffTest.kt
new file mode 100644
index 0000000..cd0f1b0
--- /dev/null
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/AbstractApiCompilerDiffTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.apicompiler
+
+import androidx.privacysandbox.tools.testing.AbstractDiffTest
+import androidx.privacysandbox.tools.testing.CompilationTestHelper
+import androidx.room.compiler.processing.util.Source
+import java.nio.file.Path
+import kotlin.io.path.createDirectories
+import kotlin.io.path.createFile
+import kotlin.io.path.writeText
+
+/** Base test class for API Compiler diff testing. */
+abstract class AbstractApiCompilerDiffTest : AbstractDiffTest() {
+
+    open val extraProcessorOptions: Map<String, String> = mapOf()
+
+    override fun generateSources(
+        inputSources: List<Source>,
+        outputDirectory: Path
+    ): List<Source> {
+        val result = compileWithPrivacySandboxKspCompiler(inputSources, extraProcessorOptions)
+        CompilationTestHelper.assertThat(result).succeeds()
+        val sources = result.generatedSources
+
+        // Writing generated sources to expected output directory.
+        sources.forEach { source ->
+            outputDirectory.resolve(source.relativePath).apply {
+                parent?.createDirectories()
+                createFile()
+                writeText(source.contents)
+            }
+        }
+        return sources
+    }
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt
new file mode 100644
index 0000000..8f53ceb
--- /dev/null
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.apicompiler
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Test the Privacy Sandbox API Compiler with an SDK that uses all available features. */
+@RunWith(JUnit4::class)
+class FullFeaturedSdkApiCompilerDiffTest : AbstractApiCompilerDiffTest() {
+    override val subdirectoryName = "fullfeaturedsdk"
+    override val relativePathsToExpectedAidlClasses = listOf(
+        "com/mysdk/ICancellationSignal.java",
+        "com/mysdk/IMyCallback.java",
+        "com/mysdk/IMyInterface.java",
+        "com/mysdk/IMyInterfaceTransactionCallback.java",
+        "com/mysdk/IMySdk.java",
+        "com/mysdk/IMySecondInterface.java",
+        "com/mysdk/IMyUiInterface.java",
+        "com/mysdk/IMyUiInterfaceCoreLibInfoAndBinderWrapper.java",
+        "com/mysdk/IMyUiInterfaceTransactionCallback.java",
+        "com/mysdk/IMySecondInterfaceTransactionCallback.java",
+        "com/mysdk/IResponseTransactionCallback.java",
+        "com/mysdk/IStringTransactionCallback.java",
+        "com/mysdk/IUnitTransactionCallback.java",
+        "com/mysdk/IListResponseTransactionCallback.java",
+        "com/mysdk/IListIntTransactionCallback.java",
+        "com/mysdk/IListLongTransactionCallback.java",
+        "com/mysdk/IListDoubleTransactionCallback.java",
+        "com/mysdk/IListStringTransactionCallback.java",
+        "com/mysdk/IListBooleanTransactionCallback.java",
+        "com/mysdk/IListFloatTransactionCallback.java",
+        "com/mysdk/IListCharTransactionCallback.java",
+        "com/mysdk/IListShortTransactionCallback.java",
+        "com/mysdk/ParcelableRequest.java",
+        "com/mysdk/ParcelableResponse.java",
+        "com/mysdk/ParcelableStackFrame.java",
+        "com/mysdk/ParcelableInnerValue.java",
+        "com/mysdk/PrivacySandboxThrowableParcel.java",
+    )
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkTest.kt
deleted file mode 100644
index 9e0343d..0000000
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkTest.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.privacysandbox.tools.apicompiler
-
-import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertThat
-import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
-import java.io.File
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-/** Test the Privacy Sandbox API Compiler with an SDK that uses all available features. */
-@RunWith(JUnit4::class)
-class FullFeaturedSdkTest {
-    @Test
-    fun compileServiceInterface_ok() {
-        val inputTestDataDir = File("src/test/test-data/fullfeaturedsdk/input")
-        val outputTestDataDir = File("src/test/test-data/fullfeaturedsdk/output")
-        val inputSources = loadSourcesFromDirectory(inputTestDataDir)
-        val expectedKotlinSources = loadSourcesFromDirectory(outputTestDataDir)
-
-        val result = compileWithPrivacySandboxKspCompiler(inputSources)
-        assertThat(result).succeeds()
-
-        val expectedAidlFilepath = listOf(
-            "com/mysdk/ICancellationSignal.java",
-            "com/mysdk/IMyCallback.java",
-            "com/mysdk/IMyInterface.java",
-            "com/mysdk/IMyInterfaceTransactionCallback.java",
-            "com/mysdk/IMySdk.java",
-            "com/mysdk/IMySecondInterface.java",
-            "com/mysdk/IMyUiInterface.java",
-            "com/mysdk/IMyUiInterfaceCoreLibInfoAndBinderWrapper.java",
-            "com/mysdk/IMyUiInterfaceTransactionCallback.java",
-            "com/mysdk/IMySecondInterfaceTransactionCallback.java",
-            "com/mysdk/IResponseTransactionCallback.java",
-            "com/mysdk/IStringTransactionCallback.java",
-            "com/mysdk/IUnitTransactionCallback.java",
-            "com/mysdk/IListResponseTransactionCallback.java",
-            "com/mysdk/IListIntTransactionCallback.java",
-            "com/mysdk/IListLongTransactionCallback.java",
-            "com/mysdk/IListDoubleTransactionCallback.java",
-            "com/mysdk/IListStringTransactionCallback.java",
-            "com/mysdk/IListBooleanTransactionCallback.java",
-            "com/mysdk/IListFloatTransactionCallback.java",
-            "com/mysdk/IListCharTransactionCallback.java",
-            "com/mysdk/IListShortTransactionCallback.java",
-            "com/mysdk/ParcelableRequest.java",
-            "com/mysdk/ParcelableResponse.java",
-            "com/mysdk/ParcelableStackFrame.java",
-            "com/mysdk/ParcelableInnerValue.java",
-            "com/mysdk/PrivacySandboxThrowableParcel.java",
-        )
-        assertThat(result).hasAllExpectedGeneratedSourceFilesAndContent(
-            expectedKotlinSources,
-            expectedAidlFilepath
-        )
-    }
-}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesApiCompilerDiffTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesApiCompilerDiffTest.kt
new file mode 100644
index 0000000..d9558f0
--- /dev/null
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesApiCompilerDiffTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.apicompiler
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/**
+ *  Test the Privacy Sandbox API Compiler with an SDK that defines an interface in another package.
+ */
+@RunWith(JUnit4::class)
+class SdkWithPackagesApiCompilerDiffTest : AbstractApiCompilerDiffTest() {
+    override val subdirectoryName = "sdkwithpackages"
+    override val relativePathsToExpectedAidlClasses = listOf(
+        "com/myotherpackage/IMyOtherPackageInterface.java",
+        "com/myotherpackage/ParcelableMyOtherPackageDataClass.java",
+        "com/mysdk/ICancellationSignal.java",
+        "com/mysdk/IListIntTransactionCallback.java",
+        "com/mysdk/IMyOtherPackageDataClassTransactionCallback.java",
+        "com/mysdk/IUnitTransactionCallback.java",
+        "com/mysdk/IMyOtherPackageInterfaceTransactionCallback.java",
+        "com/mysdk/IMySdk.java",
+        "com/mysdk/ParcelableStackFrame.java",
+        "com/mysdk/IStringTransactionCallback.java",
+        "com/mysdk/IMyMainPackageInterfaceTransactionCallback.java",
+        "com/mysdk/IMyMainPackageInterface.java",
+        "com/mysdk/PrivacySandboxThrowableParcel.java"
+    )
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesTest.kt
deleted file mode 100644
index 7928c89..0000000
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/SdkWithPackagesTest.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.privacysandbox.tools.apicompiler
-
-import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertThat
-import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
-import java.io.File
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-/**
- *  Test the Privacy Sandbox API Compiler with an SDK that defines an interface in another package.
- */
-@RunWith(JUnit4::class)
-class SdkWithPackagesTest {
-    @Test
-    fun compileServiceInterface_ok() {
-        val inputTestDataDir = File("src/test/test-data/sdkwithpackages/input")
-        val outputTestDataDir = File("src/test/test-data/sdkwithpackages/output")
-        val inputSources = loadSourcesFromDirectory(inputTestDataDir)
-        val expectedKotlinSources = loadSourcesFromDirectory(outputTestDataDir)
-
-        val result = compileWithPrivacySandboxKspCompiler(inputSources)
-        assertThat(result).succeeds()
-
-        val expectedAidlFilepath = listOf(
-            "com/myotherpackage/IMyOtherPackageInterface.java",
-            "com/myotherpackage/ParcelableMyOtherPackageDataClass.java",
-            "com/mysdk/ICancellationSignal.java",
-            "com/mysdk/IListIntTransactionCallback.java",
-            "com/mysdk/IMyOtherPackageDataClassTransactionCallback.java",
-            "com/mysdk/IUnitTransactionCallback.java",
-            "com/mysdk/IMyOtherPackageInterfaceTransactionCallback.java",
-            "com/mysdk/IMySdk.java",
-            "com/mysdk/ParcelableStackFrame.java",
-            "com/mysdk/IStringTransactionCallback.java",
-            "com/mysdk/IMyMainPackageInterfaceTransactionCallback.java",
-            "com/mysdk/IMyMainPackageInterface.java",
-            "com/mysdk/PrivacySandboxThrowableParcel.java"
-        )
-        assertThat(result).hasAllExpectedGeneratedSourceFilesAndContent(
-            expectedKotlinSources,
-            expectedAidlFilepath
-        )
-    }
-}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
index 553be79..e57803a 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
@@ -17,6 +17,7 @@
 package androidx.privacysandbox.tools.apicompiler
 
 import androidx.privacysandbox.tools.testing.CompilationTestHelper
+import androidx.privacysandbox.tools.testing.TestEnvironment
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.compiler.TestCompilationResult
 
@@ -33,13 +34,8 @@
     val provider = PrivacySandboxKspCompiler.Provider()
 
     val processorOptions = buildMap {
-        val aidlCompilerPath = (System.getProperty("aidl_compiler_path")
-            ?: throw IllegalArgumentException("aidl_compiler_path flag not set."))
-        put("aidl_compiler_path", aidlCompilerPath)
-        val frameworkAidlPath = (System.getProperty("framework_aidl_path")
-            ?: throw IllegalArgumentException("framework_aidl_path flag not set."))
-        put("aidl_compiler_path", aidlCompilerPath)
-        put("framework_aidl_path", frameworkAidlPath)
+        put("aidl_compiler_path", TestEnvironment.aidlCompilerPath.toString())
+        put("framework_aidl_path", TestEnvironment.frameworkAidlPath.toString())
         putAll(extraProcessorOptions)
     }
 
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkApiCompilerDiffTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkApiCompilerDiffTest.kt
new file mode 100644
index 0000000..8fcee4c
--- /dev/null
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkApiCompilerDiffTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.apicompiler
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class WithoutRuntimeLibrarySdkApiCompilerDiffTest : AbstractApiCompilerDiffTest() {
+    override val subdirectoryName = "withoutruntimelibrarysdk"
+    override val extraProcessorOptions = mapOf("skip_sdk_runtime_compat_library" to "true")
+    override val relativePathsToExpectedAidlClasses = listOf(
+        "com/mysdk/ICancellationSignal.java",
+        "com/mysdk/IWithoutRuntimeLibrarySdk.java",
+        "com/mysdk/IStringTransactionCallback.java",
+        "com/mysdk/ParcelableStackFrame.java",
+        "com/mysdk/PrivacySandboxThrowableParcel.java",
+    )
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt
deleted file mode 100644
index fa4ec0d..0000000
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/WithoutRuntimeLibrarySdkTest.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.privacysandbox.tools.apicompiler
-
-import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertThat
-import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
-import java.io.File
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class WithoutRuntimeLibrarySdkTest {
-    @Test
-    fun compileServiceInterface_ok() {
-        val inputTestDataDir = File("src/test/test-data/withoutruntimelibrarysdk/input")
-        val outputTestDataDir = File("src/test/test-data/withoutruntimelibrarysdk/output")
-        val inputSources = loadSourcesFromDirectory(inputTestDataDir)
-        val expectedKotlinSources = loadSourcesFromDirectory(outputTestDataDir)
-
-        val result = compileWithPrivacySandboxKspCompiler(
-            inputSources,
-            extraProcessorOptions = mapOf("skip_sdk_runtime_compat_library" to "true")
-        )
-        assertThat(result).succeeds()
-
-        val expectedAidlFilepath = listOf(
-            "com/mysdk/ICancellationSignal.java",
-            "com/mysdk/IWithoutRuntimeLibrarySdk.java",
-            "com/mysdk/IStringTransactionCallback.java",
-            "com/mysdk/ParcelableStackFrame.java",
-            "com/mysdk/PrivacySandboxThrowableParcel.java",
-        )
-        assertThat(result).hasAllExpectedGeneratedSourceFilesAndContent(
-            expectedKotlinSources,
-            expectedAidlFilepath
-        )
-    }
-}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apigenerator/build.gradle b/privacysandbox/tools/tools-apigenerator/build.gradle
index b509312..5ddde21 100644
--- a/privacysandbox/tools/tools-apigenerator/build.gradle
+++ b/privacysandbox/tools/tools-apigenerator/build.gradle
@@ -52,20 +52,24 @@
             dir: "${SdkHelperKt.getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
             include: "android.jar"
     ))
-    // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
-    def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.BUILD_TOOLS_VERSION}/aidl"
-    def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
-    test {
-        inputs.files(aidlCompilerPath)
-                .withPropertyName("aidl_compiler_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        inputs.files(frameworkAidlPath)
-                .withPropertyName("framework_aidl_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        doFirst {
-            systemProperty "aidl_compiler_path", aidlCompilerPath
-            systemProperty "framework_aidl_path", frameworkAidlPath
-        }
+}
+
+// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
+def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.buildToolsVersion(project)}/aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
+def testGeneratedSourcesPath = "${project.buildDir}/testGeneratedSources"
+test {
+    inputs.files(aidlCompilerPath)
+            .withPropertyName("aidl_compiler_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.files(frameworkAidlPath)
+            .withPropertyName("framework_aidl_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.dir("src/test/test-data").withPathSensitivity(PathSensitivity.RELATIVE)
+    doFirst {
+        systemProperty "aidl_compiler_path", aidlCompilerPath
+        systemProperty "framework_aidl_path", frameworkAidlPath
+        systemProperty "test_output_dir", testGeneratedSourcesPath
     }
 }
 
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/AbstractApiGeneratorDiffTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/AbstractApiGeneratorDiffTest.kt
new file mode 100644
index 0000000..feb81d0
--- /dev/null
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/AbstractApiGeneratorDiffTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.apigenerator
+
+import androidx.privacysandbox.tools.core.Metadata
+import androidx.privacysandbox.tools.testing.AbstractDiffTest
+import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertCompiles
+import androidx.privacysandbox.tools.testing.TestEnvironment
+import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
+import androidx.room.compiler.processing.util.Source
+import java.nio.file.Path
+import org.junit.Test
+
+/**
+ * Base test for API Compiler diff test. It calls the API Packager to generate true-to-production
+ * SDK API descriptors, invokes the generator and compiles the generated sources.
+ */
+abstract class AbstractApiGeneratorDiffTest : AbstractDiffTest() {
+
+    override fun generateSources(
+        inputSources: List<Source>,
+        outputDirectory: Path
+    ): List<Source> {
+        val descriptors =
+            compileIntoInterfaceDescriptorsJar(
+                inputSources,
+                mapOf(Metadata.filePath to Metadata.toolMetadata.toByteArray())
+            )
+        val generator = PrivacySandboxApiGenerator()
+        generator.generate(
+            descriptors,
+            TestEnvironment.aidlCompilerPath, TestEnvironment.frameworkAidlPath, outputDirectory)
+        return loadSourcesFromDirectory(outputDirectory.toFile())
+    }
+
+    @Test
+    fun generatedSourcesCompile() {
+        assertCompiles(generatedSources)
+    }
+}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt
deleted file mode 100644
index 349bc7f..0000000
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.privacysandbox.tools.apigenerator
-
-import androidx.privacysandbox.tools.core.Metadata
-import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertCompiles
-import androidx.privacysandbox.tools.testing.hasAllExpectedGeneratedSourceFilesAndContent
-import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
-import androidx.room.compiler.processing.util.Source
-import java.io.File
-import java.nio.file.Files
-import kotlin.io.path.Path
-import org.junit.Test
-
-abstract class BaseApiGeneratorTest {
-    abstract val inputDirectory: File
-    abstract val outputDirectory: File
-    abstract val relativePathsToExpectedAidlClasses: List<String>
-
-    private val generatedSources: List<Source> by lazy {
-        val descriptors =
-            compileIntoInterfaceDescriptorsJar(
-                loadSourcesFromDirectory(inputDirectory),
-                mapOf(Metadata.filePath to Metadata.toolMetadata.toByteArray())
-            )
-        val aidlCompilerPath = System.getProperty("aidl_compiler_path")?.let(::Path)
-            ?: throw IllegalArgumentException("aidl_compiler_path flag not set.")
-        val frameworkAidlPath = System.getProperty("framework_aidl_path")?.let(::Path)
-            ?: throw IllegalArgumentException("framework_aidl_path flag not set.")
-
-        val generator = PrivacySandboxApiGenerator()
-
-        val outputDir = Files.createTempDirectory("output").also { it.toFile().deleteOnExit() }
-        generator.generate(descriptors, aidlCompilerPath, frameworkAidlPath, outputDir)
-        loadSourcesFromDirectory(outputDir.toFile())
-    }
-
-    @Test
-    fun generatedApi_compiles() {
-        assertCompiles(generatedSources)
-    }
-
-    @Test
-    fun generatedApi_hasExpectedContents() {
-        val expectedKotlinSources = loadSourcesFromDirectory(outputDirectory)
-        hasAllExpectedGeneratedSourceFilesAndContent(
-            generatedSources,
-            expectedKotlinSources,
-            relativePathsToExpectedAidlClasses
-        )
-    }
-}
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorDiffTest.kt
similarity index 81%
rename from privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorTest.kt
rename to privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorDiffTest.kt
index 03bc25d..2c60fa7 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/CallbacksApiGeneratorDiffTest.kt
@@ -16,14 +16,12 @@
 
 package androidx.privacysandbox.tools.apigenerator
 
-import java.io.File
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class CallbacksApiGeneratorTest : BaseApiGeneratorTest() {
-    override val inputDirectory = File("src/test/test-data/callbacks/input")
-    override val outputDirectory = File("src/test/test-data/callbacks/output")
+class CallbacksApiGeneratorDiffTest : AbstractApiGeneratorDiffTest() {
+    override val subdirectoryName = "callbacks"
     override val relativePathsToExpectedAidlClasses = listOf(
         "com/sdkwithcallbacks/IMyInterface.java",
         "com/sdkwithcallbacks/ISdkCallback.java",
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorDiffTest.kt
similarity index 84%
rename from privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorTest.kt
rename to privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorDiffTest.kt
index 29664ab..e77fda56 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/InterfaceApiGeneratorDiffTest.kt
@@ -16,14 +16,12 @@
 
 package androidx.privacysandbox.tools.apigenerator
 
-import java.io.File
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class InterfaceApiGeneratorTest : BaseApiGeneratorTest() {
-    override val inputDirectory = File("src/test/test-data/interfaces/input")
-    override val outputDirectory = File("src/test/test-data/interfaces/output")
+class InterfaceApiGeneratorDiffTest : AbstractApiGeneratorDiffTest() {
+    override val subdirectoryName = "interfaces"
     override val relativePathsToExpectedAidlClasses = listOf(
         "com/sdk/IMySdk.java",
         "com/sdk/IMyInterface.java",
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
similarity index 86%
rename from privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorTest.kt
rename to privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
index 7437b18..bf87924 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
@@ -16,14 +16,12 @@
 
 package androidx.privacysandbox.tools.apigenerator
 
-import java.io.File
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class PrimitivesApiGeneratorTest : BaseApiGeneratorTest() {
-    override val inputDirectory = File("src/test/test-data/primitives/input")
-    override val outputDirectory = File("src/test/test-data/primitives/output")
+class PrimitivesApiGeneratorDiffTest : AbstractApiGeneratorDiffTest() {
+    override val subdirectoryName = "primitives"
     override val relativePathsToExpectedAidlClasses = listOf(
         "com/mysdk/ITestSandboxSdk.java",
         "com/mysdk/IBooleanTransactionCallback.java",
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorDiffTest.kt
similarity index 85%
rename from privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorTest.kt
rename to privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorDiffTest.kt
index c729c44..526e75b 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/ValuesApiGeneratorDiffTest.kt
@@ -16,14 +16,12 @@
 
 package androidx.privacysandbox.tools.apigenerator
 
-import java.io.File
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
-class ValuesApiGeneratorTest : BaseApiGeneratorTest() {
-    override val inputDirectory = File("src/test/test-data/values/input")
-    override val outputDirectory = File("src/test/test-data/values/output")
+class ValuesApiGeneratorDiffTest : AbstractApiGeneratorDiffTest() {
+    override val subdirectoryName = "values"
     override val relativePathsToExpectedAidlClasses = listOf(
         "com/sdkwithvalues/IMyInterface.java",
         "com/sdkwithvalues/ISdkInterface.java",
diff --git a/privacysandbox/tools/tools-core/build.gradle b/privacysandbox/tools/tools-core/build.gradle
index a1b06db..9e56006 100644
--- a/privacysandbox/tools/tools-core/build.gradle
+++ b/privacysandbox/tools/tools-core/build.gradle
@@ -42,20 +42,22 @@
             dir: "${SdkHelperKt.getSdkPath(project)}/platforms/$SupportConfig.COMPILE_SDK_VERSION/",
             include: "android.jar"
     ))
-    // Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
-    def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.BUILD_TOOLS_VERSION}/aidl"
-    def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
-    test {
-        inputs.files(aidlCompilerPath)
-                .withPropertyName("aidl_compiler_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        inputs.files(frameworkAidlPath)
-                .withPropertyName("framework_aidl_path")
-                .withPathSensitivity(PathSensitivity.NAME_ONLY)
-        doFirst {
-            systemProperty "aidl_compiler_path", aidlCompilerPath
-            systemProperty "framework_aidl_path", frameworkAidlPath
-        }
+}
+
+// Get AIDL compiler path and framework.aidl path and pass to tests for code generation.
+def aidlCompilerPath = "${SdkHelperKt.getSdkPath(project)}/build-tools/${SupportConfig.buildToolsVersion(project)}/aidl"
+def frameworkAidlPath = "${SdkHelperKt.getSdkPath(project)}/platforms/${SupportConfig.COMPILE_SDK_VERSION}/framework.aidl"
+test {
+    inputs.files(aidlCompilerPath)
+            .withPropertyName("aidl_compiler_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.files(frameworkAidlPath)
+            .withPropertyName("framework_aidl_path")
+            .withPathSensitivity(PathSensitivity.NAME_ONLY)
+    inputs.dir("src/test/test-data").withPathSensitivity(PathSensitivity.RELATIVE)
+    doFirst {
+        systemProperty "aidl_compiler_path", aidlCompilerPath
+        systemProperty "framework_aidl_path", frameworkAidlPath
     }
 }
 
diff --git a/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/AbstractDiffTest.kt b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/AbstractDiffTest.kt
new file mode 100644
index 0000000..bd362a5
--- /dev/null
+++ b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/AbstractDiffTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.tools.testing
+
+import androidx.room.compiler.processing.util.Source
+import com.google.common.truth.Truth
+import java.io.File
+import java.nio.file.Path
+import kotlin.io.path.Path
+import org.junit.Test
+
+/** Base test class for diff testing Privacy Sandbox tool output. */
+abstract class AbstractDiffTest {
+    /** Name for the subdirectory used to read input and expected sources. */
+    abstract val subdirectoryName: String
+
+    /**
+     * List of relative paths to expected AIDL files. We will assert that they are present in the
+     * final output but we won't check their contents.
+     */
+    abstract val relativePathsToExpectedAidlClasses: List<String>
+
+    /**
+     * Generates the sources and stores them in the given [outputDirectory].
+     * @param inputSources List of input sources read from the test-data directory with
+     * [subdirectoryName].
+     */
+    abstract fun generateSources(
+        inputSources: List<Source>,
+        outputDirectory: Path,
+    ): List<Source>
+
+    protected val generatedSources: List<Source> by lazy {
+        val inputSources =
+            loadSourcesFromDirectory(File("src/test/test-data/$subdirectoryName/input"))
+        outputDir.toFile().also {
+            if (it.exists()) {
+                it.deleteRecursively()
+            }
+            it.mkdirs()
+        }
+        generateSources(inputSources, outputDir)
+    }
+
+    @Test
+    fun generatedSourcesHaveExpectedContents() {
+        val expectedKotlinSources =
+            loadSourcesFromDirectory(File("src/test/test-data/$subdirectoryName/output"))
+
+        val expectedRelativePaths =
+            expectedKotlinSources.map(Source::relativePath) + relativePathsToExpectedAidlClasses
+        Truth.assertThat(generatedSources.map(Source::relativePath))
+            .containsExactlyElementsIn(expectedRelativePaths)
+
+        val actualRelativePathMap = generatedSources.associateBy(Source::relativePath)
+        for (expectedKotlinSource in expectedKotlinSources) {
+            Truth.assertWithMessage(
+                "Contents of generated file ${expectedKotlinSource.relativePath} don't " +
+                    "match golden. Here's the path to generated sources: $outputDir"
+            ).that(actualRelativePathMap[expectedKotlinSource.relativePath]?.contents)
+                .isEqualTo(expectedKotlinSource.contents)
+        }
+    }
+
+    private val outputDir: Path by lazy {
+        requireNotNull(System.getProperty("test_output_dir")) {
+            "test_output_dir not set for diff test."
+        }.let { Path(it).resolve(subdirectoryName) }
+    }
+}
\ No newline at end of file
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/TestEnvironment.kt
similarity index 60%
copy from bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
copy to privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/TestEnvironment.kt
index 84d9567..2a65ddd 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
+++ b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/TestEnvironment.kt
@@ -14,11 +14,16 @@
  * limitations under the License.
  */
 
-package androidx.bluetooth.integration.testapp.data
+package androidx.privacysandbox.tools.testing
 
-import android.os.ParcelUuid
+import kotlin.io.path.Path
 
-object SampleAdvertiseData {
-    val testUUID: ParcelUuid =
-        ParcelUuid.fromString("00000000-0000-0000-0000-000000000001")
-}
+object TestEnvironment {
+    val aidlCompilerPath = requireNotNull(System.getProperty("aidl_compiler_path")) {
+        "aidl_compiler_path flag not set"
+    }.let(::Path)
+
+    val frameworkAidlPath = requireNotNull(System.getProperty("framework_aidl_path")) {
+        "framework_aidl_path flag not set."
+    }.let(::Path)
+}
\ No newline at end of file
diff --git a/profileinstaller/integration-tests/profile-verification/build.gradle b/profileinstaller/integration-tests/profile-verification/build.gradle
index a25c998..aa13d76 100644
--- a/profileinstaller/integration-tests/profile-verification/build.gradle
+++ b/profileinstaller/integration-tests/profile-verification/build.gradle
@@ -63,8 +63,10 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.testUiautomator)
     androidTestImplementation(libs.testExtTruth)
+    androidTestImplementation(project(":core:core"))
     apkAssets(project(":profileinstaller:integration-tests:profile-verification-sample"))
     apkAssets(project(":profileinstaller:integration-tests:profile-verification-sample-no-initializer"))
+    apkAssets(project(":benchmark:integration-tests:baselineprofile-consumer"))
 }
 
 // It makes sure that the apks are generated before the assets are packed.
diff --git a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnGeneratedProfiles.kt b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnGeneratedProfiles.kt
new file mode 100644
index 0000000..0516ad7
--- /dev/null
+++ b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnGeneratedProfiles.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.profileinstaller.integration.profileverification
+
+import androidx.profileinstaller.ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE
+import androidx.profileinstaller.ProfileVerifier.CompilationStatus.RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
+import androidx.profileinstaller.ProfileVersion
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@SdkSuppress(
+    minSdkVersion = android.os.Build.VERSION_CODES.P,
+    maxSdkVersion = ProfileVersion.MAX_SUPPORTED_SDK
+)
+@RunWith(Parameterized::class)
+class ProfileVerificationOnGeneratedProfiles(
+    private val apk: String,
+    private val packageName: String
+) {
+
+    companion object {
+        private const val ACTIVITY_NAME = ".EmptyActivity"
+
+        @Parameterized.Parameters(name = "apk={0},packageName={1}")
+        @JvmStatic
+        fun parameters(): List<Array<Any>> = listOf(
+            arrayOf(
+                "baselineprofile-consumer-release.apk",
+                "androidx.benchmark.integration.baselineprofile.consumer"
+            )
+        )
+    }
+
+    @Before
+    fun setUp() {
+        // TODO: to re-enable for api 34 (b/276970167)
+        Assume.assumeTrue(!isApi34)
+
+        // Note that this test fails on emulator api 30 (b/251540646)
+        Assume.assumeTrue(!isApi30)
+        withPackageName(packageName) { uninstall() }
+    }
+
+    @After
+    fun tearDown() {
+        withPackageName(packageName) { uninstall() }
+    }
+
+    @Test
+    fun generatedBaselineProfile() =
+        withPackageName(packageName) {
+
+            // Installs the apk
+            install(apkName = apk, withProfile = false)
+
+            // Check that a profile exists and it's enqueued for compilation
+            start(ACTIVITY_NAME)
+            evaluateUI {
+                profileInstalled(RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION)
+                hasReferenceProfile(false)
+                hasCurrentProfile(true)
+            }
+            stop()
+
+            // Compile app with enqueued profile
+            compileCurrentProfile()
+
+            // Checks that the app has been compiled with a profile
+            start(ACTIVITY_NAME)
+            evaluateUI {
+                profileInstalled(RESULT_CODE_COMPILED_WITH_PROFILE)
+                hasReferenceProfile(true)
+                hasCurrentProfile(false)
+            }
+        }
+}
diff --git a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnUnsupportedApiVersions.kt b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnUnsupportedApiVersions.kt
index 834bffec..34cc956 100644
--- a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnUnsupportedApiVersions.kt
+++ b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationOnUnsupportedApiVersions.kt
@@ -29,6 +29,8 @@
 
     @Before
     fun setUp() {
+        // TODO: to re-enable for api 34 (b/276970167)
+        Assume.assumeTrue(!isApi34)
 
         // This test runs only on selected api version currently unsupported by profile verifier
         Assume.assumeTrue(
diff --git a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithProfileInstallerInitializer.kt b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithProfileInstallerInitializer.kt
index 20cff54..fe47284 100644
--- a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithProfileInstallerInitializer.kt
+++ b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithProfileInstallerInitializer.kt
@@ -47,6 +47,9 @@
 
     @Before
     fun setUp() = withPackageName(PACKAGE_NAME_WITH_INITIALIZER) {
+        // TODO: to re-enable for api 34 (b/276970167)
+        assumeTrue(!isApi34)
+
         // Note that this test fails on emulator api 30 (b/251540646)
         assumeTrue(!isApi30)
         uninstall()
diff --git a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithoutProfileInstallerInitializer.kt b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithoutProfileInstallerInitializer.kt
index cca5f12..63401b6 100644
--- a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithoutProfileInstallerInitializer.kt
+++ b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/ProfileVerificationTestWithoutProfileInstallerInitializer.kt
@@ -50,6 +50,9 @@
 
     @Before
     fun setUp() = withPackageName(PACKAGE_NAME_WITHOUT_INITIALIZER) {
+        // TODO: to re-enable for api 34 (b/276970167)
+        assumeTrue(!isApi34)
+
         // Note that this test fails on emulator api 30 (b/251540646)
         assumeTrue(!isApi30)
         uninstall()
diff --git a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/TestManager.kt b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/TestManager.kt
index fc1796d..91647ac 100644
--- a/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/TestManager.kt
+++ b/profileinstaller/integration-tests/profile-verification/src/androidTest/java/androidx/profileinstaller/integration/profileverification/TestManager.kt
@@ -21,6 +21,7 @@
 import android.os.ParcelFileDescriptor
 import android.util.Log
 import androidx.concurrent.futures.DirectExecutor
+import androidx.core.os.BuildCompat
 import androidx.profileinstaller.DeviceProfileWriter
 import androidx.profileinstaller.ProfileInstaller
 import androidx.test.platform.app.InstrumentationRegistry
@@ -300,6 +301,7 @@
 private fun <T> T?.throwIfNull(message: String): T = this ?: throw Exception(message)
 
 val isApi30 by lazy { Build.VERSION.SDK_INT == Build.VERSION_CODES.R }
+val isApi34 by lazy { BuildCompat.isAtLeastU() }
 
 const val PACKAGE_NAME_WITH_INITIALIZER =
     "androidx.profileinstaller.integration.profileverification.target"
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
index 7543f34..4fbbfbb 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
@@ -117,14 +117,29 @@
             return false;
         }
 
-        if (!mCurProfile.canWrite()) {
-            // It's possible that some OEMs might not allow writing to this directory. If this is
-            // the case, there's not really anything we can do, so we should quit before doing
-            // any unnecessary work.
-            result(ProfileInstaller.RESULT_NOT_WRITABLE, null);
-            return false;
+        // Check if the current profile file can be written. In Android U the current profile is
+        // no more created empty at app startup, so we need to deal with both file already existing
+        // and not existing. When the file exists, we just want to make sure that it's writeable.
+        // When the file does not exist, we want to make sure that it can be created.
+        // If this is not possible on the device, there is nothing we can do. This behavior might
+        // also be customized by OEM, that could prevent writing this file.
+        if (mCurProfile.exists()) {
+            if (!mCurProfile.canWrite()) {
+                result(ProfileInstaller.RESULT_NOT_WRITABLE, null);
+                return false;
+            }
+        } else {
+            try {
+                mCurProfile.createNewFile();
+            } catch (IOException e) {
+                // If the file cannot be created it's the same of the profile file not being
+                // writeable
+                result(ProfileInstaller.RESULT_NOT_WRITABLE, null);
+                return false;
+            }
         }
 
+
         mDeviceSupportsAotProfile = true;
         return true;
     }
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewOnGenericMotionEventTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewOnGenericMotionEventTest.java
index 289e033..f489478 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewOnGenericMotionEventTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewOnGenericMotionEventTest.java
@@ -24,9 +24,13 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.widget.OverScroller;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
 import androidx.core.view.InputDeviceCompat;
 import androidx.core.view.ViewConfigurationCompat;
 import androidx.test.core.app.ApplicationProvider;
@@ -57,17 +61,71 @@
     }
 
     @Test
-    public void rotaryEncoderVerticalScroll() {
+    public void rotaryEncoderVerticalScroll_nonLowResDevice() {
+        mRecyclerView.mLowResRotaryEncoderFeature = false;
+        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+
+        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()),
+                /* assertSmoothScroll= */ false);
+    }
+
+    @Test
+    public void rotaryEncoderHorizontalScroll_nonLowResDevice() {
+        mRecyclerView.mLowResRotaryEncoderFeature = false;
+        // The encoder is one-dimensional, and can only scroll horizontally if vertical scrolling
+        // is not enabled.
+        MockLayoutManager layoutManager = new MockLayoutManager(true, false);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+
+        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0,
+                /* assertSmoothScroll= */ false);
+    }
+
+    @Test
+    public void rotaryEncoderVerticalScroll_lowResDevice() {
+        mRecyclerView.mLowResRotaryEncoderFeature = true;
         MockLayoutManager layoutManager = new MockLayoutManager(true, true);
         mRecyclerView.setLayoutManager(layoutManager);
         layout();
         TouchUtils.scrollView(
                 MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
-        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
+        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()),
+                /* assertSmoothScroll= */ true);
     }
 
     @Test
-    public void rotaryEncoderHorizontalScroll() {
+    public void rotaryEncoderVerticalScroll_lowResDevice_backToBackScrollEvents() {
+        mRecyclerView.mLowResRotaryEncoderFeature = true;
+        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+        OverScroller overScroller = mRecyclerView.mViewFlinger.mOverScroller;
+        int remainingScroll = overScroller.getFinalY() - overScroller.getCurrY();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+
+        // The expected total scroll will be the amount corresponding to each of the two scroll
+        // events, plus the amount of scroll remaining from the first scroll by the time the
+        // second scroll was initiated.
+        assertTotalScroll(0, (int) (-4f * getScaledVerticalScrollFactor()) + remainingScroll,
+                /* assertSmoothScroll= */ true);
+    }
+
+    @Test
+    public void rotaryEncoderHorizontalScroll_lowResDevice() {
+        mRecyclerView.mLowResRotaryEncoderFeature = true;
         // The encoder is one-dimensional, and can only scroll horizontally if vertical scrolling
         // is not enabled.
         MockLayoutManager layoutManager = new MockLayoutManager(true, false);
@@ -75,7 +133,29 @@
         layout();
         TouchUtils.scrollView(
                 MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
-        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
+        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0,
+                /* assertSmoothScroll= */ true);
+    }
+
+    @Test
+    public void rotaryEncoderHorizontalScroll_lowResDevice_backToBackScrollEvents() {
+        mRecyclerView.mLowResRotaryEncoderFeature = true;
+        MockLayoutManager layoutManager = new MockLayoutManager(true, false);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+        OverScroller overScroller = mRecyclerView.mViewFlinger.mOverScroller;
+        int remainingScroll = overScroller.getFinalX() - overScroller.getCurrX();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+
+        // The expected total scroll will be the amount corresponding to each of the two scroll
+        // events, plus the amount of scroll remaining from the first scroll by the time the
+        // second scroll was initiated.
+        assertTotalScroll((int) (4f * getScaledVerticalScrollFactor()) + remainingScroll, 0,
+                /* assertSmoothScroll= */ true);
     }
 
     @Test
@@ -109,8 +189,17 @@
     }
 
     private void assertTotalScroll(int x, int y) {
-        assertEquals("x total scroll", x, mRecyclerView.mTotalX);
-        assertEquals("y total scroll", y, mRecyclerView.mTotalY);
+        assertTotalScroll(x, y, /* smoothScroll= */ false);
+    }
+
+    private void assertTotalScroll(int x, int y, boolean assertSmoothScroll) {
+        if (assertSmoothScroll) {
+            assertEquals("x total smooth scroll", x, mRecyclerView.mTotalSmoothX);
+            assertEquals("y total smooth scroll", y, mRecyclerView.mTotalSmoothY);
+        } else {
+            assertEquals("x total scroll", x, mRecyclerView.mTotalX);
+            assertEquals("y total scroll", y, mRecyclerView.mTotalY);
+        }
     }
 
     private static MotionEvent obtainScrollMotionEvent(int axis, int axisValue, int inputDevice) {
@@ -212,6 +301,9 @@
         int mTotalX = 0;
         int mTotalY = 0;
 
+        int mTotalSmoothX = 0;
+        int mTotalSmoothY = 0;
+
         TestRecyclerView(Context context) {
             super(context);
         }
@@ -221,5 +313,12 @@
             mTotalY += y;
             return super.scrollByInternal(x, y, ev, type);
         }
+
+        void smoothScrollBy(@Px int dx, @Px int dy, @Nullable Interpolator interpolator,
+                int duration, boolean withNestedScrolling) {
+            mTotalSmoothX += dx;
+            mTotalSmoothY += dy;
+            super.smoothScrollBy(dx, dy, interpolator, duration, withNestedScrolling);
+        }
     }
 }
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
index 6325804..db5526b 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
@@ -283,6 +283,18 @@
      */
     private static final float FLING_DESTRETCH_FACTOR = 4f;
 
+    /**
+     * A {@link android.content.pm.PackageManager} feature specifying if a device's rotary encoder
+     * has low resolution. Low resolution rotary encoders produce small number of
+     * {@link MotionEvent}s per a 360 degree rotation, meaning that each {@link MotionEvent} has
+     * large scroll values, which make {@link #scrollBy(int, int)} calls feel broken (due to the
+     * fact that each event produces large scrolls, and scrolling with large pixels causes a visible
+     * jump that does not feel smooth). As such, we will try adjusting our handling of generic
+     * motion caused by such low resolution rotary encoders differently to make the scrolling
+     * experience smooth.
+     */
+    static final String LOW_RES_ROTARY_ENCODER_FEATURE = "android.hardware.rotaryencoder.lowres";
+
     static final boolean DISPATCH_TEMP_DETACH = false;
 
     @RestrictTo(LIBRARY_GROUP_PREFIX)
@@ -690,6 +702,12 @@
     private int mLastAutoMeasureNonExactMeasuredHeight = 0;
 
     /**
+     * Whether or not the device has {@link #LOW_RES_ROTARY_ENCODER_FEATURE}. Computed once and
+     * cached, since it's a static value that would not change on consecutive calls.
+     */
+    @VisibleForTesting boolean mLowResRotaryEncoderFeature;
+
+    /**
      * The callback to convert view info diffs into animations.
      */
     private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
@@ -799,6 +817,9 @@
         }
         a.recycle();
 
+        mLowResRotaryEncoderFeature =
+                context.getPackageManager().hasSystemFeature(LOW_RES_ROTARY_ENCODER_FEATURE);
+
         // Create the layoutManager if specified.
         createLayoutManager(context, layoutManagerName, attrs, defStyleAttr, 0);
 
@@ -3948,6 +3969,8 @@
         if (mLayoutSuppressed) {
             return false;
         }
+
+        boolean useSmoothScroll = false;
         if (event.getAction() == MotionEvent.ACTION_SCROLL) {
             final float vScroll, hScroll;
             if ((event.getSource() & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) {
@@ -3977,14 +4000,25 @@
                     vScroll = 0f;
                     hScroll = 0f;
                 }
+                // Use smooth scrolling for low resolution rotary encoders to avoid the visible
+                // pixel jumps that would be caused by doing regular scrolling.
+                useSmoothScroll = mLowResRotaryEncoderFeature;
             } else {
                 vScroll = 0f;
                 hScroll = 0f;
             }
 
-            if (vScroll != 0 || hScroll != 0) {
-                nestedScrollByInternal((int) (hScroll * mScaledHorizontalScrollFactor),
-                        (int) (vScroll * mScaledVerticalScrollFactor), event, TYPE_NON_TOUCH);
+            int scaledVScroll = (int) (vScroll * mScaledVerticalScrollFactor);
+            int scaledHScroll = (int) (hScroll * mScaledHorizontalScrollFactor);
+            if (useSmoothScroll) {
+                OverScroller overScroller = mViewFlinger.mOverScroller;
+                // Account for any remaining scroll from a previous generic motion event.
+                scaledVScroll += overScroller.getFinalY() - overScroller.getCurrY();
+                scaledHScroll += overScroller.getFinalX() - overScroller.getCurrX();
+                smoothScrollBy(scaledHScroll, scaledVScroll, /* interpolator= */ null,
+                        UNDEFINED_DURATION, /* withNestedScrolling= */ true);
+            } else {
+                nestedScrollByInternal(scaledHScroll, scaledVScroll, event, TYPE_NON_TOUCH);
             }
         }
         return false;
diff --git a/room/room-common/api/current.txt b/room/room-common/api/current.txt
index fea0995..95d009b 100644
--- a/room/room-common/api/current.txt
+++ b/room/room-common/api/current.txt
@@ -377,7 +377,7 @@
     field public static final String PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED = "ROOM_EMBEDDED_PRIMARY_KEY_IS_DROPPED";
     field public static final String RELATION_QUERY_WITHOUT_TRANSACTION = "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
     field public static final String RELATION_TYPE_MISMATCH = "ROOM_RELATION_TYPE_MISMATCH";
-    field public static final String ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
+    field public static final String UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
   }
 
   public static final class RoomWarnings.Companion {
diff --git a/room/room-common/api/public_plus_experimental_current.txt b/room/room-common/api/public_plus_experimental_current.txt
index fea0995..95d009b 100644
--- a/room/room-common/api/public_plus_experimental_current.txt
+++ b/room/room-common/api/public_plus_experimental_current.txt
@@ -377,7 +377,7 @@
     field public static final String PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED = "ROOM_EMBEDDED_PRIMARY_KEY_IS_DROPPED";
     field public static final String RELATION_QUERY_WITHOUT_TRANSACTION = "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
     field public static final String RELATION_TYPE_MISMATCH = "ROOM_RELATION_TYPE_MISMATCH";
-    field public static final String ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
+    field public static final String UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
   }
 
   public static final class RoomWarnings.Companion {
diff --git a/room/room-common/api/restricted_current.txt b/room/room-common/api/restricted_current.txt
index a7f714c..139f37e 100644
--- a/room/room-common/api/restricted_current.txt
+++ b/room/room-common/api/restricted_current.txt
@@ -386,7 +386,7 @@
     field public static final String PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED = "ROOM_EMBEDDED_PRIMARY_KEY_IS_DROPPED";
     field public static final String RELATION_QUERY_WITHOUT_TRANSACTION = "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
     field public static final String RELATION_TYPE_MISMATCH = "ROOM_RELATION_TYPE_MISMATCH";
-    field public static final String ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
+    field public static final String UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE = "ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE";
   }
 
   public static final class RoomWarnings.Companion {
diff --git a/room/room-common/src/main/java/androidx/room/RoomWarnings.kt b/room/room-common/src/main/java/androidx/room/RoomWarnings.kt
index c8bcfb5..8031af0 100644
--- a/room/room-common/src/main/java/androidx/room/RoomWarnings.kt
+++ b/room/room-common/src/main/java/androidx/room/RoomWarnings.kt
@@ -205,8 +205,8 @@
          * Room will return an empty Collection, Array or Optional respectively if no results are
          * returned by such a query, hence using a nullable return type is unnecessary in this case.
          */
-        public const val ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE: String =
-            "UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE"
+        public const val UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE: String =
+            "ROOM_UNNECESSARY_NULLABILITY_IN_DAO_RETURN_TYPE"
     }
 
     @Deprecated("This type should not be instantiated as it contains only static methods. ")
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
index 447fbf3..66b4c84 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/synthetic/KspSyntheticContinuationParameterElement.kt
@@ -55,20 +55,21 @@
     override fun isKotlinPropertyParam() = false
 
     override val name: String by lazy {
-        // KAPT uses `continuation` but it doesn't check for conflicts, we do.
-        var candidate = "continuation"
+        // KAPT uses `$completion` but it doesn't check for conflicts, we do. Be aware that before
+        // Kotlin 1.8.0 the param was named 'continuation'.
+        var candidate = PARAM_NAME
         var suffix = 0
         while (
             enclosingElement.declaration.parameters.any { it.name?.asString() == candidate }
         ) {
-            candidate = "continuation_$suffix"
+            candidate = PARAM_NAME + "_" + suffix
             suffix ++
         }
         candidate
     }
 
     override val equalityItems: Array<out Any?> by lazy {
-        arrayOf("continuation", enclosingElement)
+        arrayOf(PARAM_NAME, enclosingElement)
     }
 
     override val hasDefaultValue: Boolean
@@ -145,4 +146,8 @@
     override fun hashCode(): Int {
         return XEquality.hashCode(equalityItems)
     }
+
+    companion object {
+        const val PARAM_NAME = "\$completion"
+    }
 }
diff --git a/room/room-compiler/build.gradle b/room/room-compiler/build.gradle
index 08515b3..6b7096e 100644
--- a/room/room-compiler/build.gradle
+++ b/room/room-compiler/build.gradle
@@ -274,8 +274,10 @@
 // make sure we validate published artifacts on the build server.
 BuildOnServerKt.addToBuildOnServer(project, checkArtifactContentsTask)
 
-tasks.findByName("compileKotlin").dependsOn(generateAntlrTask)
-tasks.findByName("sourceJar").dependsOn(generateAntlrTask)
+def tasksThatDependOnAntlr = ["compileKotlin", "sourceJar", "kotlinSourcesJar", "generateKmpDocs"]
+tasks.matching { tasksThatDependOnAntlr.contains(it.name) }.configureEach {
+    it.dependsOn(generateAntlrTask)
+}
 
 tasks.withType(KotlinCompile).configureEach {
     kotlinOptions {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/result/PreparedQueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/result/PreparedQueryResultAdapter.kt
index 7d6a09d..18406e2 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/result/PreparedQueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/result/PreparedQueryResultAdapter.kt
@@ -73,6 +73,9 @@
             } else {
                 "executeUpdateDelete"
             }
+            if (preparedStmtProperty != null) {
+                beginControlFlow("try")
+            }
             addStatement("%N.beginTransaction()", dbProperty)
             beginControlFlow("try").apply {
                 if (returnType.isVoid() || returnType.isVoidObject() || returnType.isKotlinUnit()) {
@@ -97,11 +100,13 @@
             }
             nextControlFlow("finally").apply {
                 addStatement("%N.endTransaction()", dbProperty)
-                if (preparedStmtProperty != null) {
-                    addStatement("%N.release(%L)", preparedStmtProperty, stmtQueryVal)
-                }
             }
             endControlFlow()
+            if (preparedStmtProperty != null) {
+                nextControlFlow("finally")
+                addStatement("%N.release(%L)", preparedStmtProperty, stmtQueryVal)
+                endControlFlow()
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
index e5efa51..41fd15f 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
@@ -129,7 +129,7 @@
         )
         compileInEachDefaultsMode(source) { generated ->
             generated.contains("public Object upsert(final User obj, " +
-                "final Continuation<? super Unit> continuation)")
+                "final Continuation<? super Unit> \$completion)")
             if (jvmDefaultMode == JvmDefaultMode.DISABLE) {
                 generated.contains("SubjectDao.DefaultImpls.upsert(SubjectDao_Impl.this")
             } else {
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
index 58b7677..598d267 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
@@ -287,13 +287,16 @@
         final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
         int _argIndex = 1;
         _stmt.bindLong(_argIndex, uid);
-        __db.beginTransaction();
         try {
-            final int _result = _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
-            return _result;
+            __db.beginTransaction();
+            try {
+                final int _result = _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+                return _result;
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfDeleteByUid.release(_stmt);
         }
     }
@@ -307,13 +310,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return null;
+                    __db.beginTransaction();
+                    try {
+                        _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return null;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -329,13 +335,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -351,13 +360,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -368,13 +380,16 @@
     public int deleteEverything() {
         __db.assertNotSuspendingTransaction();
         final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteEverything.acquire();
-        __db.beginTransaction();
         try {
-            final int _result = _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
-            return _result;
+            __db.beginTransaction();
+            try {
+                final int _result = _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+                return _result;
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfDeleteEverything.release(_stmt);
         }
     }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
index 8873083..e3b6103 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
@@ -363,12 +363,15 @@
         } else {
             _stmt.bindString(_argIndex, uid);
         }
-        __db.beginTransaction();
         try {
-            _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
+            __db.beginTransaction();
+            try {
+                _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfAgeUserByUid.release(_stmt);
         }
     }
@@ -377,12 +380,15 @@
     public void ageUserAll() {
         __db.assertNotSuspendingTransaction();
         final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-        __db.beginTransaction();
         try {
-            _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
+            __db.beginTransaction();
+            try {
+                _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfAgeUserAll.release(_stmt);
         }
     }
@@ -394,13 +400,16 @@
             @Nullable
             public Void call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return null;
+                    __db.beginTransaction();
+                    try {
+                        _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return null;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
@@ -414,13 +423,16 @@
             @Nullable
             public Integer call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
@@ -434,13 +446,16 @@
             @Nullable
             public Integer call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
index a8478f5..4fa7155 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
@@ -281,13 +281,16 @@
         final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
         int _argIndex = 1;
         _stmt.bindLong(_argIndex, uid);
-        __db.beginTransaction();
         try {
-            final int _result = _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
-            return _result;
+            __db.beginTransaction();
+            try {
+                final int _result = _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+                return _result;
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfDeleteByUid.release(_stmt);
         }
     }
@@ -301,13 +304,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return null;
+                    __db.beginTransaction();
+                    try {
+                        _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return null;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -323,13 +329,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -345,13 +354,16 @@
                 final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteByUid.acquire();
                 int _argIndex = 1;
                 _stmt.bindLong(_argIndex, uid);
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfDeleteByUid.release(_stmt);
                 }
             }
@@ -362,13 +374,16 @@
     public int deleteEverything() {
         __db.assertNotSuspendingTransaction();
         final SupportSQLiteStatement _stmt = __preparedStmtOfDeleteEverything.acquire();
-        __db.beginTransaction();
         try {
-            final int _result = _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
-            return _result;
+            __db.beginTransaction();
+            try {
+                final int _result = _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+                return _result;
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfDeleteEverything.release(_stmt);
         }
     }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
index a17d135..571e245 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
@@ -330,12 +330,15 @@
         final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserByUid.acquire();
         int _argIndex = 1;
         _stmt.bindString(_argIndex, uid);
-        __db.beginTransaction();
         try {
-            _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
+            __db.beginTransaction();
+            try {
+                _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfAgeUserByUid.release(_stmt);
         }
     }
@@ -344,12 +347,15 @@
     public void ageUserAll() {
         __db.assertNotSuspendingTransaction();
         final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-        __db.beginTransaction();
         try {
-            _stmt.executeUpdateDelete();
-            __db.setTransactionSuccessful();
+            __db.beginTransaction();
+            try {
+                _stmt.executeUpdateDelete();
+                __db.setTransactionSuccessful();
+            } finally {
+                __db.endTransaction();
+            }
         } finally {
-            __db.endTransaction();
             __preparedStmtOfAgeUserAll.release(_stmt);
         }
     }
@@ -361,13 +367,16 @@
             @Nullable
             public Void call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return null;
+                    __db.beginTransaction();
+                    try {
+                        _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return null;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
@@ -381,13 +390,16 @@
             @Nullable
             public Integer call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
@@ -401,13 +413,16 @@
             @Nullable
             public Integer call() throws Exception {
                 final SupportSQLiteStatement _stmt = __preparedStmtOfAgeUserAll.acquire();
-                __db.beginTransaction();
                 try {
-                    final Integer _result = _stmt.executeUpdateDelete();
-                    __db.setTransactionSuccessful();
-                    return _result;
+                    __db.beginTransaction();
+                    try {
+                        final Integer _result = _stmt.executeUpdateDelete();
+                        __db.setTransactionSuccessful();
+                        return _result;
+                    } finally {
+                        __db.endTransaction();
+                    }
                 } finally {
-                    __db.endTransaction();
                     __preparedStmtOfAgeUserAll.release(_stmt);
                 }
             }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
index c2562be..e7ff72b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
@@ -38,13 +38,16 @@
         val _stmt: SupportSQLiteStatement = __preparedStmtOfInsertEntity.acquire()
         var _argIndex: Int = 1
         _stmt.bindLong(_argIndex, id)
-        __db.beginTransaction()
         try {
-            val _result: Long = _stmt.executeInsert()
-            __db.setTransactionSuccessful()
-            return _result
+            __db.beginTransaction()
+            try {
+                val _result: Long = _stmt.executeInsert()
+                __db.setTransactionSuccessful()
+                return _result
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfInsertEntity.release(_stmt)
         }
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx2.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx2.kt
index eeee3c0..9bbf6ad 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx2.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx2.kt
@@ -41,13 +41,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    val _result: Long? = _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return _result
+                    __db.beginTransaction()
+                    try {
+                        val _result: Long? = _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return _result
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
@@ -61,13 +64,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    val _result: Long? = _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return _result
+                    __db.beginTransaction()
+                    try {
+                        val _result: Long? = _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return _result
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
@@ -81,13 +87,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return null
+                    __db.beginTransaction()
+                    try {
+                        _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return null
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx3.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx3.kt
index f6d72eb..81bb13a 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx3.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedCallableQuery_rx3.kt
@@ -41,13 +41,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    val _result: Long? = _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return _result
+                    __db.beginTransaction()
+                    try {
+                        val _result: Long? = _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return _result
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
@@ -61,13 +64,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    val _result: Long? = _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return _result
+                    __db.beginTransaction()
+                    try {
+                        val _result: Long? = _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return _result
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
@@ -81,13 +87,16 @@
                 _stmt.bindString(_argIndex, id)
                 _argIndex = 2
                 _stmt.bindString(_argIndex, name)
-                __db.beginTransaction()
                 try {
-                    _stmt.executeInsert()
-                    __db.setTransactionSuccessful()
-                    return null
+                    __db.beginTransaction()
+                    try {
+                        _stmt.executeInsert()
+                        __db.setTransactionSuccessful()
+                        return null
+                    } finally {
+                        __db.endTransaction()
+                    }
                 } finally {
-                    __db.endTransaction()
                     __preparedStmtOfInsertPublisherSingle.release(_stmt)
                 }
             }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedQueryAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedQueryAdapter.kt
index 65888262..8ce5067 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedQueryAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/preparedQueryAdapter.kt
@@ -58,12 +58,15 @@
         val _stmt: SupportSQLiteStatement = __preparedStmtOfInsertEntity.acquire()
         var _argIndex: Int = 1
         _stmt.bindLong(_argIndex, id)
-        __db.beginTransaction()
         try {
-            _stmt.executeInsert()
-            __db.setTransactionSuccessful()
+            __db.beginTransaction()
+            try {
+                _stmt.executeInsert()
+                __db.setTransactionSuccessful()
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfInsertEntity.release(_stmt)
         }
     }
@@ -73,13 +76,16 @@
         val _stmt: SupportSQLiteStatement = __preparedStmtOfInsertEntity.acquire()
         var _argIndex: Int = 1
         _stmt.bindLong(_argIndex, id)
-        __db.beginTransaction()
         try {
-            val _result: Long = _stmt.executeInsert()
-            __db.setTransactionSuccessful()
-            return _result
+            __db.beginTransaction()
+            try {
+                val _result: Long = _stmt.executeInsert()
+                __db.setTransactionSuccessful()
+                return _result
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfInsertEntity.release(_stmt)
         }
     }
@@ -89,12 +95,15 @@
         val _stmt: SupportSQLiteStatement = __preparedStmtOfUpdateEntity.acquire()
         var _argIndex: Int = 1
         _stmt.bindString(_argIndex, text)
-        __db.beginTransaction()
         try {
-            _stmt.executeUpdateDelete()
-            __db.setTransactionSuccessful()
+            __db.beginTransaction()
+            try {
+                _stmt.executeUpdateDelete()
+                __db.setTransactionSuccessful()
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfUpdateEntity.release(_stmt)
         }
     }
@@ -106,13 +115,16 @@
         _stmt.bindString(_argIndex, text)
         _argIndex = 2
         _stmt.bindLong(_argIndex, id)
-        __db.beginTransaction()
         try {
-            val _result: Int = _stmt.executeUpdateDelete()
-            __db.setTransactionSuccessful()
-            return _result
+            __db.beginTransaction()
+            try {
+                val _result: Int = _stmt.executeUpdateDelete()
+                __db.setTransactionSuccessful()
+                return _result
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfUpdateEntityReturnInt.release(_stmt)
         }
     }
@@ -120,12 +132,15 @@
     public override fun deleteEntity(): Unit {
         __db.assertNotSuspendingTransaction()
         val _stmt: SupportSQLiteStatement = __preparedStmtOfDeleteEntity.acquire()
-        __db.beginTransaction()
         try {
-            _stmt.executeUpdateDelete()
-            __db.setTransactionSuccessful()
+            __db.beginTransaction()
+            try {
+                _stmt.executeUpdateDelete()
+                __db.setTransactionSuccessful()
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfDeleteEntity.release(_stmt)
         }
     }
@@ -133,13 +148,16 @@
     public override fun deleteEntityReturnInt(): Int {
         __db.assertNotSuspendingTransaction()
         val _stmt: SupportSQLiteStatement = __preparedStmtOfDeleteEntity.acquire()
-        __db.beginTransaction()
         try {
-            val _result: Int = _stmt.executeUpdateDelete()
-            __db.setTransactionSuccessful()
-            return _result
+            __db.beginTransaction()
+            try {
+                val _result: Int = _stmt.executeUpdateDelete()
+                __db.setTransactionSuccessful()
+                return _result
+            } finally {
+                __db.endTransaction()
+            }
         } finally {
-            __db.endTransaction()
             __preparedStmtOfDeleteEntity.release(_stmt)
         }
     }
diff --git a/settings.gradle b/settings.gradle
index 6d43ec6..51235a5 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -88,7 +88,7 @@
             value("BUILD_NUMBER", BUILD_NUMBER)
             link("ci.android.com build", "https://ci.android.com/builds/branches/aosp-androidx-main/grid?head=$BUILD_NUMBER&tail=$BUILD_NUMBER")
         }
-
+        value("androidx.compose.multiplatformEnabled", isMultiplatformEnabled().toString())
         value("androidx.projects", getRequestedProjectSubsetName() ?: "Unset")
         value("androidx.useMaxDepVersions", providers.gradleProperty("androidx.useMaxDepVersions").isPresent().toString())
 
@@ -170,6 +170,12 @@
     }
 }
 
+boolean isMultiplatformEnabled() {
+    def mppParameter = properties.get("androidx.compose.multiplatformEnabled")
+    if (mppParameter == null) return false
+    return Boolean.parseBoolean(mppParameter)
+}
+
 /////////////////////////////
 //
 // Buildscript utils
@@ -187,7 +193,6 @@
     GLANCE,
     TOOLS,
     KMP,
-    INFRAROGUE,
     CAMERA,
     NATIVE,
     WINDOW,
@@ -245,9 +250,6 @@
             case "KMP":
                 filter.add(BuildType.KMP)
                 break
-            case "INFRAROGUE":
-                filter.add(BuildType.INFRAROGUE)
-                break
             case "CAMERA":
                 filter.add(BuildType.CAMERA)
                 break
@@ -343,13 +345,13 @@
 //
 /////////////////////////////
 
-includeProject(":activity:activity", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.KMP, BuildType.WEAR])
-includeProject(":activity:activity-compose", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":activity:activity-compose:activity-compose-samples", "activity/activity-compose/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":activity:activity", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
+includeProject(":activity:activity-compose", [BuildType.COMPOSE])
+includeProject(":activity:activity-compose:activity-compose-samples", "activity/activity-compose/samples", [BuildType.COMPOSE])
 includeProject(":activity:activity-compose:integration-tests:activity-demos", [BuildType.COMPOSE])
-includeProject(":activity:activity-compose-lint", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":activity:activity-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.KMP, BuildType.WEAR])
-includeProject(":activity:activity-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.KMP, BuildType.WEAR])
+includeProject(":activity:activity-compose-lint", [BuildType.COMPOSE])
+includeProject(":activity:activity-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
+includeProject(":activity:activity-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":activity:integration-tests:testapp", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":annotation:annotation")
 includeProject(":annotation:annotation-experimental")
@@ -381,18 +383,18 @@
 includeProject(":appsearch:appsearch-local-storage", [BuildType.MAIN])
 includeProject(":appsearch:appsearch-platform-storage", [BuildType.MAIN])
 includeProject(":appsearch:appsearch-test-util", [BuildType.MAIN])
-includeProject(":arch:core:core-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":arch:core:core-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":arch:core:core-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":arch:core:core-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":arch:core:core-testing", [BuildType.MAIN])
 includeProject(":asynclayoutinflater:asynclayoutinflater", [BuildType.MAIN])
 includeProject(":asynclayoutinflater:asynclayoutinflater-appcompat", [BuildType.MAIN])
 includeProject(":autofill:autofill", [BuildType.MAIN])
 includeProject(":benchmark:benchmark-benchmark", "benchmark/benchmark", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":benchmark:benchmark-common")
-includeProject(":benchmark:benchmark-darwin", [BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":benchmark:benchmark-darwin-core", [BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":benchmark:benchmark-darwin-samples", [BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":benchmark:benchmark-darwin-gradle-plugin", [BuildType.INFRAROGUE, BuildType.KMP])
+includeProject(":benchmark:benchmark-darwin", [BuildType.KMP])
+includeProject(":benchmark:benchmark-darwin-core", [BuildType.KMP])
+includeProject(":benchmark:benchmark-darwin-samples", [BuildType.KMP])
+includeProject(":benchmark:benchmark-darwin-gradle-plugin", [BuildType.KMP])
 includeProject(":benchmark:benchmark-gradle-plugin", "benchmark/gradle-plugin", [BuildType.MAIN])
 includeProject(":benchmark:benchmark-baseline-profile-gradle-plugin", "benchmark/baseline-profile-gradle-plugin",[BuildType.MAIN])
 includeProject(":benchmark:benchmark-junit4")
@@ -461,45 +463,48 @@
 includeProject(":car:app:app-samples:showcase-mobile", "car/app/app-samples/showcase/mobile", [BuildType.MAIN])
 includeProject(":car:app:app-testing", [BuildType.MAIN])
 includeProject(":cardview:cardview", [BuildType.MAIN])
-includeProject(":collection:collection", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":collection:collection-benchmark", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":collection:collection-benchmark-kmp", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":collection:collection-ktx", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":collection:integration-tests:testapp", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":compose:animation", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:animation:animation", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:animation:animation-lint", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:animation:animation-core", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:animation:animation-core-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":collection:collection", [BuildType.MAIN, BuildType.KMP])
+includeProject(":collection:collection-benchmark", [BuildType.MAIN, BuildType.KMP])
+includeProject(":collection:collection-benchmark-kmp", [BuildType.MAIN, BuildType.KMP])
+includeProject(":collection:collection-ktx", [BuildType.MAIN, BuildType.KMP])
+includeProject(":collection:integration-tests:testapp", [BuildType.MAIN, BuildType.KMP])
+includeProject(":compose:animation", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation-lint", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation-core", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation-core-lint", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation-core:animation-core-benchmark", "compose/animation/animation-core/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:animation:animation-core:animation-core-samples", "compose/animation/animation-core/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:animation:animation-tooling-internal", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:animation:animation-core:animation-core-samples", "compose/animation/animation-core/samples", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation-tooling-internal", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation:integration-tests:animation-demos", [BuildType.COMPOSE])
-includeProject(":compose:animation:animation:animation-samples", "compose/animation/animation/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:animation:animation:animation-samples", "compose/animation/animation/samples", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation-graphics", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation-graphics:animation-graphics-samples", "compose/animation/animation-graphics/samples", [BuildType.COMPOSE])
 includeProject(":compose:benchmark-utils", [BuildType.COMPOSE])
 includeProject(":compose:benchmark-utils:benchmark-utils-benchmark", "compose/benchmark-utils/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:compiler:compiler", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
+includeProject(":compose:compiler:compiler", [BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":compose:compiler:compiler:integration-tests", [BuildType.COMPOSE])
-includeProject(":compose:compiler:compiler-hosted", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
+includeProject(":compose:compiler:compiler-hosted", [BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":compose:compiler:compiler-hosted:integration-tests", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler-hosted:integration-tests:kotlin-compiler-repackaged", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler-daemon", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler-daemon:integration-tests", [BuildType.COMPOSE])
-includeProject(":compose:desktop", [BuildType.COMPOSE])
-includeProject(":compose:desktop:desktop", [BuildType.COMPOSE])
-includeProject(":compose:desktop:desktop:desktop-samples", "compose/desktop/desktop/samples", [BuildType.COMPOSE])
-includeProject(":compose:foundation", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:foundation:foundation", [BuildType.COMPOSE, BuildType.KMP])
+
+if (isMultiplatformEnabled()) {
+    includeProject(":compose:desktop", [BuildType.COMPOSE])
+    includeProject(":compose:desktop:desktop", [BuildType.COMPOSE])
+    includeProject(":compose:desktop:desktop:desktop-samples", "compose/desktop/desktop/samples", [BuildType.COMPOSE])
+}
+includeProject(":compose:foundation", [BuildType.COMPOSE])
+includeProject(":compose:foundation:foundation", [BuildType.COMPOSE])
 includeProject(":compose:foundation:foundation-benchmark", "compose/foundation/foundation/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:foundation:foundation-layout", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:foundation:foundation-layout", [BuildType.COMPOSE])
 includeProject(":compose:foundation:foundation-layout:foundation-layout-benchmark", "compose/foundation/foundation-layout/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:foundation:foundation-layout:integration-tests:foundation-layout-demos", "compose/foundation/foundation-layout/integration-tests/layout-demos", [BuildType.COMPOSE])
-includeProject(":compose:foundation:foundation-layout:foundation-layout-samples", "compose/foundation/foundation-layout/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:foundation:foundation-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:foundation:foundation-layout:foundation-layout-samples", "compose/foundation/foundation-layout/samples", [BuildType.COMPOSE])
+includeProject(":compose:foundation:foundation-lint", [BuildType.COMPOSE])
 includeProject(":compose:foundation:foundation:integration-tests:foundation-demos", [BuildType.COMPOSE])
-includeProject(":compose:foundation:foundation:foundation-samples", "compose/foundation/foundation/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:foundation:foundation:foundation-samples", "compose/foundation/foundation/samples", [BuildType.COMPOSE])
 includeProject(":compose:integration-tests", [BuildType.COMPOSE])
 includeProject(":compose:integration-tests:demos", [BuildType.COMPOSE])
 includeProject(":compose:integration-tests:demos:common", [BuildType.COMPOSE])
@@ -508,96 +513,97 @@
 includeProject(":compose:integration-tests:macrobenchmark-target", [BuildType.COMPOSE])
 includeProject(":compose:integration-tests:material-catalog", [BuildType.COMPOSE])
 includeProject(":compose:lint", [BuildType.COMPOSE, BuildType.CAMERA])
-includeProject(":compose:lint:internal-lint-checks", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
-includeProject(":compose:lint:common", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
-includeProject(":compose:lint:common-test", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
+includeProject(":compose:lint:internal-lint-checks", [BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":compose:lint:common", [BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":compose:lint:common-test", [BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":compose:material", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3", [BuildType.COMPOSE])
 includeProject(":compose:material3:benchmark", [BuildType.COMPOSE])
-includeProject(":compose:material3:material3-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:material3:material3-adaptive", [BuildType.COMPOSE])
+includeProject(":compose:material3:material3-lint", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-window-size-class", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-window-size-class:material3-window-size-class-samples", "compose/material3/material3-window-size-class/samples", [BuildType.COMPOSE])
-includeProject(":compose:material:material", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:material:material", [BuildType.COMPOSE])
 includeProject(":compose:material:material-benchmark", "compose/material/material/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:material:material-lint", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-core", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-core:material-icons-core-samples", "compose/material/material-icons-core/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended-filled", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended-outlined", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended-rounded", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended-sharp", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-icons-extended-twotone", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material-ripple", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:material:material:icons:generator", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:material:material-lint", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-core", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-core:material-icons-core-samples", "compose/material/material-icons-core/samples", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended-filled", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended-outlined", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended-rounded", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended-sharp", [BuildType.COMPOSE])
+includeProject(":compose:material:material-icons-extended-twotone", [BuildType.COMPOSE])
+includeProject(":compose:material:material-ripple", [BuildType.COMPOSE])
+includeProject(":compose:material:material:icons:generator", [BuildType.COMPOSE])
 includeProject(":compose:material:material:integration-tests:material-demos", [BuildType.COMPOSE])
 includeProject(":compose:material:material:integration-tests:material-catalog", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3:integration-tests:material3-demos", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3:integration-tests:material3-catalog", [BuildType.COMPOSE])
-includeProject(":compose:material:material:material-samples", "compose/material/material/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:material:material:material-samples", "compose/material/material/samples", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3:material3-samples", "compose/material3/material3/samples", [BuildType.COMPOSE])
-includeProject(":compose:runtime", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
-includeProject(":compose:runtime:runtime", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
-includeProject(":compose:runtime:runtime-lint", [BuildType.COMPOSE, BuildType.CAMERA, BuildType.KMP])
-includeProject(":compose:runtime:runtime-livedata", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:runtime:runtime-livedata:runtime-livedata-samples", "compose/runtime/runtime-livedata/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:runtime", [BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":compose:runtime:runtime", [BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":compose:runtime:runtime-lint", [BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":compose:runtime:runtime-livedata", [BuildType.COMPOSE])
+includeProject(":compose:runtime:runtime-livedata:runtime-livedata-samples", "compose/runtime/runtime-livedata/samples", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime-tracing", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime-rxjava2", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime-rxjava2:runtime-rxjava2-samples", "compose/runtime/runtime-rxjava2/samples", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime-rxjava3", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime-rxjava3:runtime-rxjava3-samples", "compose/runtime/runtime-rxjava3/samples", [BuildType.COMPOSE])
-includeProject(":compose:runtime:runtime-saveable", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:runtime:runtime-saveable-lint", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:runtime:runtime-saveable:runtime-saveable-samples", "compose/runtime/runtime-saveable/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:runtime:runtime-saveable", [BuildType.COMPOSE])
+includeProject(":compose:runtime:runtime-saveable-lint", [BuildType.COMPOSE])
+includeProject(":compose:runtime:runtime-saveable:runtime-saveable-samples", "compose/runtime/runtime-saveable/samples", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime:benchmark", "compose/runtime/runtime/compose-runtime-benchmark", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime:integration-tests", [BuildType.COMPOSE])
 includeProject(":compose:runtime:runtime:runtime-samples", "compose/runtime/runtime/samples", [BuildType.COMPOSE, BuildType.CAMERA])
-includeProject(":compose:test-utils", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:test-utils", [BuildType.COMPOSE])
+includeProject(":compose:ui", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-benchmark", "compose/ui/ui/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:ui:ui-android-stubs", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-geometry", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-graphics", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-graphics-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:ui:ui-android-stubs", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-geometry", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-graphics", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-graphics-lint", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-graphics:ui-graphics-benchmark", "compose/ui/ui-graphics/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-graphics:ui-graphics-benchmark:test", [BuildType.COMPOSE])
-includeProject(":compose:ui:ui-graphics:ui-graphics-samples", "compose/ui/ui-graphics/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-inspection", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-lint", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-test", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-test:ui-test-samples", "compose/ui/ui-test/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-test-junit4", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-test-manifest", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-test-manifest-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:ui:ui-graphics:ui-graphics-samples", "compose/ui/ui-graphics/samples", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-inspection", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-lint", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-test", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-test:ui-test-samples", "compose/ui/ui-test/samples", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-test-junit4", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-test-manifest", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-test-manifest-lint", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-test-manifest:integration-tests:testapp", [BuildType.COMPOSE])
-includeProject(":compose:ui:ui-text", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:ui:ui-text", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-text-google-fonts", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-text:ui-text-benchmark", "compose/ui/ui-text/benchmark", [BuildType.COMPOSE])
-includeProject(":compose:ui:ui-text:ui-text-samples", "compose/ui/ui-text/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-tooling", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-tooling-data", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-tooling-preview", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-unit", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-unit:ui-unit-samples", "compose/ui/ui-unit/samples", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":compose:ui:ui-util", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:ui:ui-text:ui-text-samples", "compose/ui/ui-text/samples", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-tooling", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-tooling-data", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-tooling-preview", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-unit", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-unit:ui-unit-samples", "compose/ui/ui-unit/samples", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-util", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-viewbinding", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-viewbinding:ui-viewbinding-samples", "compose/ui/ui-viewbinding/samples", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui:integration-tests:ui-demos", [BuildType.COMPOSE])
-includeProject(":compose:ui:ui:ui-samples", "compose/ui/ui/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":compose:ui:ui:ui-samples", "compose/ui/ui/samples", [BuildType.COMPOSE])
 includeProject(":concurrent:concurrent-futures", [BuildType.MAIN, BuildType.CAMERA, BuildType.COMPOSE])
 includeProject(":concurrent:concurrent-futures-ktx", [BuildType.MAIN, BuildType.CAMERA])
-includeProject(":constraintlayout:constraintlayout-compose", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":constraintlayout:constraintlayout-compose-lint", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":constraintlayout:constraintlayout-compose", [BuildType.COMPOSE])
+includeProject(":constraintlayout:constraintlayout-compose-lint", [BuildType.COMPOSE])
 includeProject(":constraintlayout:constraintlayout-compose:integration-tests:demos", [BuildType.COMPOSE])
 includeProject(":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark", [BuildType.COMPOSE])
 includeProject(":constraintlayout:constraintlayout-compose:integration-tests:macrobenchmark-target", [BuildType.COMPOSE])
 includeProject(":constraintlayout:constraintlayout", [BuildType.MAIN])
-includeProject(":constraintlayout:constraintlayout-core", [BuildType.MAIN, BuildType.COMPOSE, BuildType.KMP])
+includeProject(":constraintlayout:constraintlayout-core", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":contentpager:contentpager", [BuildType.MAIN])
 includeProject(":coordinatorlayout:coordinatorlayout", [BuildType.MAIN])
-includeProject(":core:core", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR, BuildType.KMP])
-includeProject(":core:core-testing", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR, BuildType.KMP])
+includeProject(":core:core", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
+includeProject(":core:core-testing", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":core:core:integration-tests:publishing", [BuildType.MAIN])
 includeProject(":core:core-animation", [BuildType.MAIN])
 includeProject(":core:core-animation-integration-tests:testapp", [BuildType.MAIN])
@@ -605,7 +611,7 @@
 includeProject(":core:core-appdigest", [BuildType.MAIN])
 includeProject(":core:core-google-shortcuts", [BuildType.MAIN])
 includeProject(":core:core-i18n", [BuildType.MAIN])
-includeProject(":core:core-ktx", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR, BuildType.KMP])
+includeProject(":core:core-ktx", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":core:core-location-altitude", [BuildType.MAIN])
 includeProject(":core:core-performance", [BuildType.MAIN])
 includeProject(":core:core-performance:core-performance-samples", "core/core-performance/samples", [BuildType.MAIN])
@@ -623,19 +629,20 @@
 includeProject(":cursoradapter:cursoradapter", [BuildType.MAIN])
 includeProject(":customview:customview", [BuildType.MAIN])
 includeProject(":customview:customview-poolingcontainer", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":datastore:datastore", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-core", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-core-okio", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
+includeProject(":datastore:datastore", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-benchmark", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-core", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-core-okio", [BuildType.MAIN, BuildType.KMP])
 includeProject(":datastore:datastore-compose-samples", [BuildType.COMPOSE])
-includeProject(":datastore:datastore-preferences", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-preferences-core", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-preferences-proto", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-preferences-rxjava2", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-preferences-rxjava3", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-proto", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-rxjava2", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-rxjava3", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":datastore:datastore-sampleapp", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
+includeProject(":datastore:datastore-preferences", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-preferences-core", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-preferences-proto", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-preferences-rxjava2", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-preferences-rxjava3", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-proto", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-rxjava2", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-rxjava3", [BuildType.MAIN, BuildType.KMP])
+includeProject(":datastore:datastore-sampleapp", [BuildType.MAIN, BuildType.KMP])
 includeProject(":documentfile:documentfile", [BuildType.MAIN])
 includeProject(":draganddrop:draganddrop", [BuildType.MAIN])
 includeProject(":draganddrop:integration-tests:sampleapp", [BuildType.MAIN])
@@ -648,7 +655,7 @@
 includeProject(":emoji:emoji", [BuildType.MAIN])
 includeProject(":emoji:emoji-appcompat", [BuildType.MAIN])
 includeProject(":emoji:emoji-bundled", [BuildType.MAIN])
-includeProject(":emoji2:emoji2", [BuildType.MAIN, BuildType.COMPOSE, BuildType.KMP])
+includeProject(":emoji2:emoji2", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":emoji2:emoji2-bundled", [BuildType.MAIN])
 includeProject(":emoji2:emoji2-views", [BuildType.MAIN])
 includeProject(":emoji2:emoji2-views-helper", [BuildType.MAIN])
@@ -676,11 +683,12 @@
 includeProject(":glance:glance-appwidget:integration-tests:demos", [BuildType.GLANCE])
 includeProject(":glance:glance-appwidget:integration-tests:macrobenchmark", [BuildType.GLANCE])
 includeProject(":glance:glance-appwidget:integration-tests:macrobenchmark-target", [BuildType.GLANCE])
-includeProject(":glance:glance-appwidget:integration-tests:template-demos", [BuildType.GLANCE])
 includeProject(":glance:glance-appwidget:glance-layout-generator", [BuildType.GLANCE])
 includeProject(":glance:glance-preview", [BuildType.GLANCE])
 includeProject(":glance:glance-material", [BuildType.GLANCE])
 includeProject(":glance:glance-material3", [BuildType.GLANCE])
+includeProject(":glance:glance-template", [BuildType.GLANCE])
+includeProject(":glance:glance-template:integration-tests:template-demos", [BuildType.GLANCE])
 includeProject(":glance:glance-wear-tiles:integration-tests:demos", [BuildType.GLANCE])
 includeProject(":glance:glance-wear-tiles:integration-tests:template-demos", [BuildType.GLANCE])
 includeProject(":glance:glance-wear-tiles", [BuildType.GLANCE])
@@ -706,9 +714,9 @@
 includeProject(":hilt:integration-tests:hilt-testapp-viewmodel", "hilt/integration-tests/viewmodelapp", [BuildType.MAIN])
 includeProject(":hilt:integration-tests:hilt-testapp-worker", "hilt/integration-tests/workerapp", [BuildType.MAIN])
 includeProject(":input:input-motionprediction", [BuildType.MAIN])
-includeProject(":inspection:inspection", [BuildType.MAIN, BuildType.COMPOSE, BuildType.KMP])
+includeProject(":inspection:inspection", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":inspection:inspection-gradle-plugin", [BuildType.MAIN])
-includeProject(":inspection:inspection-testing", [BuildType.MAIN, BuildType.COMPOSE, BuildType.KMP])
+includeProject(":inspection:inspection-testing", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":interpolator:interpolator", [BuildType.MAIN])
 includeProject(":javascriptengine:javascriptengine", [BuildType.MAIN])
 includeProject(":leanback:leanback", [BuildType.MAIN])
@@ -719,33 +727,33 @@
 includeProject(":lifecycle:integration-tests:incrementality", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:integration-tests:lifecycle-testapp", "lifecycle/integration-tests/testapp", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:integration-tests:lifecycle-testapp-kotlin", "lifecycle/integration-tests/kotlintestapp", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-common-java8", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-common-java8", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lifecycle:lifecycle-compiler", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:lifecycle-extensions", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-livedata", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-livedata-core", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-livedata-core-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-livedata-core-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lifecycle:lifecycle-livedata-core-truth", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-livedata-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lifecycle:lifecycle-process", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:lifecycle-reactivestreams", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:lifecycle-reactivestreams-ktx", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lifecycle:lifecycle-runtime-compose", [BuildType.COMPOSE])
 includeProject(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples", "lifecycle/lifecycle-runtime-compose/samples", [BuildType.COMPOSE])
 includeProject(":lifecycle:lifecycle-runtime-compose:integration-tests:lifecycle-runtime-compose-demos", [BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-runtime-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-runtime-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-runtime-testing", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime-testing", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lifecycle:lifecycle-service", [BuildType.MAIN, BuildType.FLAN, BuildType.GLANCE])
-includeProject(":lifecycle:lifecycle-viewmodel", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-viewmodel-compose", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":lifecycle:lifecycle-viewmodel-compose:lifecycle-viewmodel-compose-samples", "lifecycle/lifecycle-viewmodel-compose/samples", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":lifecycle:lifecycle-viewmodel", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-viewmodel-compose", [BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-viewmodel-compose:lifecycle-viewmodel-compose-samples", "lifecycle/lifecycle-viewmodel-compose/samples", [BuildType.COMPOSE])
 includeProject(":lifecycle:lifecycle-viewmodel-compose:integration-tests:lifecycle-viewmodel-demos", [BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
-includeProject(":lifecycle:lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.KMP, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
 includeProject(":lint-checks")
 includeProject(":lint-checks:integration-tests")
 includeProject(":loader:loader", [BuildType.MAIN])
@@ -914,7 +922,7 @@
 includeProject(":vectordrawable:vectordrawable-animated", [BuildType.MAIN])
 includeProject(":vectordrawable:vectordrawable-seekable", [BuildType.MAIN])
 includeProject(":versionedparcelable:versionedparcelable", [BuildType.MAIN])
-includeProject(":versionedparcelable:versionedparcelable-compiler", [BuildType.MAIN, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR, BuildType.KMP])
+includeProject(":versionedparcelable:versionedparcelable-compiler", [BuildType.MAIN, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":viewpager2:integration-tests:testapp", [BuildType.MAIN])
 includeProject(":viewpager2:integration-tests:targetsdk-tests", [BuildType.MAIN])
 includeProject(":viewpager2:viewpager2", [BuildType.MAIN])
@@ -1048,20 +1056,20 @@
 /////////////////////////////
 
 includeProject(":internal-testutils-common", "testutils/testutils-common", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN])
-includeProject(":internal-testutils-datastore", "testutils/testutils-datastore", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP])
-includeProject(":internal-testutils-runtime", "testutils/testutils-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.KMP, BuildType.MEDIA, BuildType.WEAR, BuildType.CAMERA])
+includeProject(":internal-testutils-datastore", "testutils/testutils-datastore", [BuildType.MAIN, BuildType.KMP])
+includeProject(":internal-testutils-runtime", "testutils/testutils-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.MEDIA, BuildType.WEAR, BuildType.CAMERA])
 includeProject(":internal-testutils-appcompat", "testutils/testutils-appcompat", [BuildType.MAIN])
 includeProject(":internal-testutils-espresso", "testutils/testutils-espresso", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":internal-testutils-fonts", "testutils/testutils-fonts", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.KMP, BuildType.WEAR])
+includeProject(":internal-testutils-fonts", "testutils/testutils-fonts", [BuildType.MAIN, BuildType.GLANCE, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":internal-testutils-truth", "testutils/testutils-truth")
 includeProject(":internal-testutils-ktx", "testutils/testutils-ktx")
-includeProject(":internal-testutils-kmp", "testutils/testutils-kmp", [BuildType.MAIN, BuildType.INFRAROGUE, BuildType.KMP, BuildType.COMPOSE])
+includeProject(":internal-testutils-kmp", "testutils/testutils-kmp", [BuildType.MAIN, BuildType.KMP, BuildType.COMPOSE])
 includeProject(":internal-testutils-macrobenchmark", "testutils/testutils-macrobenchmark", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":internal-testutils-navigation", "testutils/testutils-navigation", [BuildType.MAIN, BuildType.COMPOSE, BuildType.FLAN])
 includeProject(":internal-testutils-paging", "testutils/testutils-paging", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":internal-testutils-paparazzi", "testutils/testutils-paparazzi", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":internal-testutils-paparazzi", "testutils/testutils-paparazzi", [BuildType.COMPOSE])
 includeProject(":internal-testutils-gradle-plugin", "testutils/testutils-gradle-plugin", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.TOOLS])
-includeProject(":internal-testutils-mockito", "testutils/testutils-mockito", [BuildType.MAIN, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR, BuildType.KMP])
+includeProject(":internal-testutils-mockito", "testutils/testutils-mockito", [BuildType.MAIN, BuildType.MEDIA, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 
 /////////////////////////////
 //
@@ -1100,16 +1108,16 @@
 includeProject(":icing:nativeLib", new File(externalRoot, "icing/nativeLib"), [BuildType.MAIN])
 includeProject(":external:libyuv", [BuildType.CAMERA])
 includeProject(":noto-emoji-compat-font", new File(externalRoot, "noto-fonts/emoji-compat"), [BuildType.MAIN])
-includeProject(":noto-emoji-compat-flatbuffers", new File(externalRoot, "noto-fonts/emoji-compat-flatbuffers"), [BuildType.MAIN, BuildType.COMPOSE, BuildType.KMP])
-includeProject(":external:paparazzi:paparazzi", [BuildType.COMPOSE, BuildType.KMP])
-includeProject(":external:paparazzi:paparazzi-agent", [BuildType.COMPOSE, BuildType.KMP])
+includeProject(":noto-emoji-compat-flatbuffers", new File(externalRoot, "noto-fonts/emoji-compat-flatbuffers"), [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":external:paparazzi:paparazzi", [BuildType.COMPOSE])
+includeProject(":external:paparazzi:paparazzi-agent", [BuildType.COMPOSE])
 
 if (isAllProjects()) {
     includeProject(":docs-tip-of-tree")
     includeProject(":docs-public")
 }
 
-includeProject(":docs-kmp", [BuildType.KMP, BuildType.INFRAROGUE])
+includeProject(":docs-kmp", [BuildType.KMP])
 // placeholder test project that has a test for each size to ensure that at least one test is run
 // for each size and test runner is happy when there is nothing to test.
 includeProject(":placeholder-tests")
diff --git a/slidingpanelayout/OWNERS b/slidingpanelayout/OWNERS
index eadd41a..9f68f2d 100644
--- a/slidingpanelayout/OWNERS
+++ b/slidingpanelayout/OWNERS
@@ -1,3 +1,4 @@
 # Bug component: 461510
 [email protected]
 [email protected]
[email protected]
\ No newline at end of file
diff --git a/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/matchers/MSSIMMatcher.kt b/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/matchers/MSSIMMatcher.kt
index 915c248..ca12d74 100644
--- a/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/matchers/MSSIMMatcher.kt
+++ b/test/screenshot/screenshot/src/main/java/androidx/test/screenshot/matchers/MSSIMMatcher.kt
@@ -210,6 +210,12 @@
         windowWidth: Int,
         windowHeight: Int
     ): DoubleArray {
+        if (windowHeight == 1 && windowWidth == 1) {
+            // There is only one item. The variance of a single item would be 0.
+            // Since Bessel's correction is used below, it will return NaN instead of 0.
+            return doubleArrayOf(0.0, 0.0, 0.0)
+        }
+
         var var0 = 0.0
         var var1 = 0.0
         var varBoth = 0.0
@@ -223,9 +229,11 @@
                 varBoth += v0 * v1
             }
         }
-        var0 /= windowWidth * windowHeight - 1.toDouble()
-        var1 /= windowWidth * windowHeight - 1.toDouble()
-        varBoth /= windowWidth * windowHeight - 1.toDouble()
+        // Using Bessel's correction. Hence, subtracting one.
+        val denominatorWithBesselsCorrection = windowWidth * windowHeight - 1.0
+        var0 /= denominatorWithBesselsCorrection
+        var1 /= denominatorWithBesselsCorrection
+        varBoth /= denominatorWithBesselsCorrection
         return doubleArrayOf(var0, var1, varBoth)
     }
 
@@ -244,4 +252,4 @@
         l += 0.07f * (Color.blue(pixel) / 255f.toDouble()).pow(gamma)
         return l
     }
-}
\ No newline at end of file
+}
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
index aa853d7..91bfcab 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
@@ -19,6 +19,8 @@
 import android.util.Log;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import androidx.annotation.NonNull;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -27,8 +29,8 @@
 import java.util.regex.Pattern;
 
 /**
- * A utility class which provides static methods for searching the {@link AccessibilityNodeInfo}
- * hierarchy for nodes that match {@link BySelector} criteria.
+ * Provides utility methods for searching the {@link AccessibilityNodeInfo} hierarchy for nodes
+ * that match {@link BySelector}s.
  */
 class ByMatcher {
 
@@ -39,12 +41,10 @@
     private final boolean mShortCircuit;
 
     /**
-     * Constructs a new {@link ByMatcher} instance. Used by
-     * {@link ByMatcher#findMatch(UiDevice, BySelector, AccessibilityNodeInfo...)} to store state information
-     * that does not change during recursive calls.
+     * Constructs a {@link ByMatcher} instance to store parameters for recursive searches.
      *
-     * @param selector The criteria used to determine if a {@link AccessibilityNodeInfo} is a match.
-     * @param shortCircuit If true, this method will return early when the first match is found.
+     * @param selector     search criteria
+     * @param shortCircuit true to stop searching when the first match is found
      */
     private ByMatcher(UiDevice device, BySelector selector, boolean shortCircuit) {
         mDevice = device;
@@ -53,19 +53,11 @@
     }
 
     /**
-     * Traverses the {@link AccessibilityNodeInfo} hierarchy starting at each {@code root} and
-     * returns the first node to match the {@code selector} criteria. <br />
-     * <strong>Note:</strong> The caller must release the {@link AccessibilityNodeInfo} instance by
-     * calling {@link AccessibilityNodeInfo#recycle()} to avoid leaking resources.
-     *
-     * @param device A reference to the {@link UiDevice}.
-     * @param selector The {@link BySelector} criteria used to determine if a node is a match.
-     * @return The first {@link AccessibilityNodeInfo} which matched the search criteria.
+     * Searches the hierarchy under each root for a node that matches the selector.
+     * <p>Note: call {@link AccessibilityNodeInfo#recycle()} when done to avoid leaking resources.
      */
     static AccessibilityNodeInfo findMatch(UiDevice device, BySelector selector,
             AccessibilityNodeInfo... roots) {
-
-        // TODO: Don't short-circuit when debugging, and warn if more than one match.
         ByMatcher matcher = new ByMatcher(device, selector, true);
         for (AccessibilityNodeInfo root : roots) {
             List<AccessibilityNodeInfo> matches = matcher.findMatches(root);
@@ -77,18 +69,11 @@
     }
 
     /**
-     * Traverses the {@link AccessibilityNodeInfo} hierarchy starting at each {@code root} and
-     * returns a list of nodes which match the {@code selector} criteria. <br />
-     * <strong>Note:</strong> The caller must release each {@link AccessibilityNodeInfo} instance
-     * by calling {@link AccessibilityNodeInfo#recycle()} to avoid leaking resources.
-     *
-     * @param device A reference to the {@link UiDevice}.
-     * @param selector The {@link BySelector} criteria used to determine if a node is a match.
-     * @return A list containing all of the nodes which matched the search criteria.
+     * Searches the hierarchy under each root for nodes that match the selector.
+     * <p>Note: call {@link AccessibilityNodeInfo#recycle()} when done to avoid leaking resources.
      */
     static List<AccessibilityNodeInfo> findMatches(UiDevice device, BySelector selector,
             AccessibilityNodeInfo... roots) {
-
         List<AccessibilityNodeInfo> ret = new ArrayList<>();
         ByMatcher matcher = new ByMatcher(device, selector, false);
         for (AccessibilityNodeInfo root : roots) {
@@ -97,43 +82,27 @@
         return ret;
     }
 
-    /**
-     * Traverses the {@link AccessibilityNodeInfo} hierarchy starting at {@code root}, and returns
-     * a list of nodes which match the {@code selector} criteria. <br />
-     * <strong>Note:</strong> The caller must release each {@link AccessibilityNodeInfo} instance
-     * by calling {@link AccessibilityNodeInfo#recycle()} to avoid leaking resources.
-     *
-     * @param root The root {@link AccessibilityNodeInfo} from which to start the search.
-     * @return A list containing all of the nodes which matched the search criteria.
-     */
+    /** Searches the hierarchy under the root for nodes that match the selector. */
     private List<AccessibilityNodeInfo> findMatches(AccessibilityNodeInfo root) {
-        List<AccessibilityNodeInfo> ret =
-                findMatches(root, 0, 0, new SinglyLinkedList<>());
-
-        // If no matches were found
+        List<AccessibilityNodeInfo> ret = findMatches(root, 0, new PartialMatchList());
         if (ret.isEmpty()) {
-            // Run watchers and retry
+            // No matches found, run watchers and retry.
             mDevice.runWatchers();
-            ret = findMatches(root, 0, 0, new SinglyLinkedList<>());
+            ret = findMatches(root, 0, new PartialMatchList());
         }
-
         return ret;
     }
 
     /**
-     * Traverses the {@link AccessibilityNodeInfo} hierarchy starting at {@code node}, and returns
-     * a list of nodes which match the {@code selector} criteria. <br />
-     * <strong>Note:</strong> The caller must release each {@link AccessibilityNodeInfo} instance
-     * by calling {@link AccessibilityNodeInfo#recycle()} to avoid leaking resources.
+     * Recursively searches a node's hierarchy for nodes that match the search criteria.
      *
-     * @param node The root of the {@link AccessibilityNodeInfo} subtree we are currently searching.
-     * @param index The index of this node underneath its parent.
-     * @param depth The distance between {@code node} and the root node.
-     * @param partialMatches The current list of {@link PartialMatch}es that need to be updated.
-     * @return A {@link List} of {@link AccessibilityNodeInfo}s that meet the search criteria.
+     * @param node           node to search
+     * @param depth          distance between the node and the search root
+     * @param partialMatches list of potential matches to track
+     * @return list of matching nodes
      */
-    private List<AccessibilityNodeInfo> findMatches(AccessibilityNodeInfo node,
-            int index, int depth, SinglyLinkedList<PartialMatch> partialMatches) {
+    private List<AccessibilityNodeInfo> findMatches(AccessibilityNodeInfo node, int depth,
+            PartialMatchList partialMatches) {
         List<AccessibilityNodeInfo> ret = new ArrayList<>();
 
         // Don't bother searching the subtree if it is not visible
@@ -144,13 +113,13 @@
 
         // Update partial matches
         for (PartialMatch partialMatch : partialMatches) {
-            partialMatches = partialMatch.update(node, index, depth, partialMatches);
+            partialMatches = partialMatch.matchChildren(node, depth, partialMatches);
         }
 
         // Create a new match, if necessary
-        PartialMatch currentMatch = PartialMatch.accept(node, mSelector, index, depth);
+        PartialMatch currentMatch = PartialMatch.create(mSelector, node, depth, depth);
         if (currentMatch != null) {
-            partialMatches = SinglyLinkedList.prepend(currentMatch, partialMatches);
+            partialMatches = partialMatches.prepend(currentMatch);
         }
 
         // For each child
@@ -168,7 +137,7 @@
             }
 
             // Add any matches found under the child subtree
-            ret.addAll(findMatches(child, i, depth + 1, partialMatches));
+            ret.addAll(findMatches(child, depth + 1, partialMatches));
 
             // We're done with the child
             child.recycle();
@@ -180,180 +149,141 @@
         }
 
         // Finalize match, if necessary
-        if (currentMatch != null && currentMatch.finalizeMatch()) {
+        if (currentMatch != null && currentMatch.isComplete()) {
             ret.add(AccessibilityNodeInfo.obtain(node));
         }
 
         return ret;
     }
 
-    /** Helper method used to evaluate a {@link Pattern} criteria if it is set. */
-    static boolean checkCriteria(Pattern criteria, CharSequence value) {
-        if (criteria == null) {
-            return true;
-        }
-        return criteria.matcher(value != null ? value : "").matches();
-    }
-
-    /** Helper method used to evaluate a {@link Boolean} criteria if it is set. */
-    static boolean checkCriteria(Boolean criteria, boolean value) {
-        if (criteria == null) {
-            return true;
-        }
-        return criteria.equals(value);
-    }
-
     /**
-     * A {@link PartialMatch} instance represents a potential match against the given
-     * {@link BySelector}. Attributes of the current node itself have been evaluated, but any child
-     * selectors have not, since we must first visit the subtree under the node before we can tell
-     * if the child selectors were matched.
+     * Represents a potential match with a {@link BySelector}. The attributes of the selector were
+     * matched, but its child selectors may not have been matched.
      */
-    static private class PartialMatch {
-        private final int matchDepth;
-        private final BySelector matchSelector;
-        private final List<PartialMatch> partialMatches = new ArrayList<>();
+    private static class PartialMatch {
+        private final BySelector mMatchSelector;
+        private final int mMatchDepth;
+        private final List<PartialMatch> mChildMatches = new ArrayList<>();
 
-        /**
-         * Private constructor. Should be instanciated by calling the
-         * {@link PartialMatch#accept(AccessibilityNodeInfo, BySelector, int, int)} factory method.
-         */
         private PartialMatch(BySelector selector, int depth) {
-            matchSelector = selector;
-            matchDepth = depth;
+            mMatchSelector = selector;
+            mMatchDepth = depth;
         }
 
         /**
-         * Factory method which returns a new {@link PartialMatch} if the node partially matches
-         * the {@code selector}, otherwise returns null.
+         * Creates a match if the provided selector matches the node.
          *
-         * @param node The node to check.
-         * @param selector The criteria used to evaluate the node.
-         * @param index The index of this node underneath its parent.
-         * @param depth The distance between {@code node} and the root node.
-         * @return A {@link PartialMatch} instance if the node matches all non-child selector
-         * criteria, otherwise null.
+         * @param selector      search criteria
+         * @param node          node to check
+         * @param absoluteDepth distance between the node and the search root
+         * @param relativeDepth distance between the node and its relevant ancestor
+         * @return potential match or null
          */
-        public static PartialMatch accept(AccessibilityNodeInfo node, BySelector selector,
-                int index, int depth) {
-            return accept(node, selector, index, depth, depth);
-        }
-
-        /**
-         * Factory method which returns a new {@link PartialMatch} if the node partially matches
-         * the {@code selector}, otherwise returns null.
-         *
-         * @param node The node to check.
-         * @param selector The criteria used to evaluate the node.
-         * @param index The index of this node underneath its parent.
-         * @param absoluteDepth The distance between {@code node} and the root node.
-         * @param relativeDepth The distance between {@code node} and the matching ancestor.
-         * @return A {@link PartialMatch} instance if the node matches all non-child selector
-         * criteria, otherwise null.
-         */
-        public static PartialMatch accept(AccessibilityNodeInfo node, BySelector selector,
-                int index, int absoluteDepth, int relativeDepth) {
-
-            if ((selector.mMinDepth != null && relativeDepth < selector.mMinDepth) ||
-                    (selector.mMaxDepth != null && relativeDepth > selector.mMaxDepth)) {
+        static PartialMatch create(BySelector selector, AccessibilityNodeInfo node,
+                int absoluteDepth, int relativeDepth) {
+            if (!matchesSelector(selector, node, relativeDepth)) {
                 return null;
             }
-
-            // NB: index is not checked, as it is not a BySelector criteria (yet). Keeping the
-            // parameter in place in case matching on index is really needed.
-
-            PartialMatch ret = null;
-            if (checkCriteria(selector.mClazz, node.getClassName()) &&
-                    checkCriteria(selector.mDesc, node.getContentDescription()) &&
-                    checkCriteria(selector.mPkg, node.getPackageName()) &&
-                    checkCriteria(selector.mRes, node.getViewIdResourceName()) &&
-                    checkCriteria(selector.mText, node.getText()) &&
-                    checkCriteria(selector.mChecked, node.isChecked()) &&
-                    checkCriteria(selector.mCheckable, node.isCheckable()) &&
-                    checkCriteria(selector.mClickable, node.isClickable()) &&
-                    checkCriteria(selector.mEnabled, node.isEnabled()) &&
-                    checkCriteria(selector.mFocused, node.isFocused()) &&
-                    checkCriteria(selector.mFocusable, node.isFocusable()) &&
-                    checkCriteria(selector.mLongClickable, node.isLongClickable()) &&
-                    checkCriteria(selector.mScrollable, node.isScrollable()) &&
-                    checkCriteria(selector.mSelected, node.isSelected())) {
-
-                ret = new PartialMatch(selector, absoluteDepth);
-            }
-            return ret;
+            return new PartialMatch(selector, absoluteDepth);
         }
 
         /**
-         * Updates this {@link PartialMatch} as part of the tree traversal. Checks to see if
-         * {@code node} matches any of the child selectors that need to match for this
-         * {@link PartialMatch} to be considered a full match.
+         * Returns true if the node matches the selector, ignoring child selectors.
          *
-         * @param node The node to process.
-         * @param index The index of this node underneath its parent.
-         * @param depth The distance between {@code node} and the root node.
-         * @param rest The list of {@link PartialMatch}es that our caller is currently tracking
-         * @return The list of {@link PartialMatch}es that our caller should track while traversing
-         * the subtree under this node.
+         * @param selector search criteria to match
+         * @param node node to check
+         * @param depth distance between the node and its relevant ancestor
          */
-        public SinglyLinkedList<PartialMatch> update(AccessibilityNodeInfo node,
-                int index, int depth, SinglyLinkedList<PartialMatch> rest) {
+        private static boolean matchesSelector(
+                BySelector selector, AccessibilityNodeInfo node, int depth) {
+            return (selector.mMinDepth == null || depth >= selector.mMinDepth)
+                    && (selector.mMaxDepth == null || depth <= selector.mMaxDepth)
+                    && matchesCriteria(selector.mClazz, node.getClassName())
+                    && matchesCriteria(selector.mDesc, node.getContentDescription())
+                    && matchesCriteria(selector.mPkg, node.getPackageName())
+                    && matchesCriteria(selector.mRes, node.getViewIdResourceName())
+                    && matchesCriteria(selector.mText, node.getText())
+                    && matchesCriteria(selector.mChecked, node.isChecked())
+                    && matchesCriteria(selector.mCheckable, node.isCheckable())
+                    && matchesCriteria(selector.mClickable, node.isClickable())
+                    && matchesCriteria(selector.mEnabled, node.isEnabled())
+                    && matchesCriteria(selector.mFocused, node.isFocused())
+                    && matchesCriteria(selector.mFocusable, node.isFocusable())
+                    && matchesCriteria(selector.mLongClickable, node.isLongClickable())
+                    && matchesCriteria(selector.mScrollable, node.isScrollable())
+                    && matchesCriteria(selector.mSelected, node.isSelected());
+        }
 
-            // Check if this node matches any of our children
-            for (BySelector childSelector : matchSelector.mChildSelectors) {
-                PartialMatch m = PartialMatch.accept(node, childSelector, index, depth,
-                        depth - matchDepth);
-                if (m != null) {
-                    partialMatches.add(m);
-                    rest = SinglyLinkedList.prepend(m, rest);
-                }
+        /** Returns true if the criteria is null or matches the value. */
+        private static boolean matchesCriteria(Pattern criteria, CharSequence value) {
+            if (criteria == null) {
+                return true;
             }
-            return rest;
+            return criteria.matcher(value != null ? value : "").matches();
+        }
+
+        /** Returns true if the criteria is null or equal to the value. */
+        private static boolean matchesCriteria(Boolean criteria, boolean value) {
+            return criteria == null || criteria.equals(value);
         }
 
         /**
-         * Finalizes this {@link PartialMatch} and returns true if it was a full match, or false
-         * otherwise.
+         * Checks whether a node matches any child selector. Creates a child match if it does and
+         * adds it to the list of tracked matches.
+         *
+         * @param node           node to check
+         * @param depth          distance between the node and the search root
+         * @param partialMatches list of matches to track
+         * @return new list of matches to track
          */
-        public boolean finalizeMatch() {
-            // Find out which of our child selectors were fully matched
-            Set<BySelector> matches = new HashSet<>();
-            for (PartialMatch p : partialMatches) {
-                if (p.finalizeMatch()) {
-                    matches.add(p.matchSelector);
+        PartialMatchList matchChildren(AccessibilityNodeInfo node, int depth,
+                PartialMatchList partialMatches) {
+            for (BySelector childSelector : mMatchSelector.mChildSelectors) {
+                PartialMatch pm = PartialMatch.create(
+                        childSelector, node, depth, depth - mMatchDepth);
+                if (pm != null) {
+                    mChildMatches.add(pm);
+                    partialMatches = partialMatches.prepend(pm);
                 }
             }
+            return partialMatches;
+        }
 
-            // Return true if matches were found for all of the child selectors
-            return matches.containsAll(matchSelector.mChildSelectors);
+        /** Returns true if all child selectors were matched. */
+        boolean isComplete() {
+            Set<BySelector> matches = new HashSet<>();
+            for (PartialMatch pm : mChildMatches) {
+                if (pm.isComplete()) {
+                    matches.add(pm.mMatchSelector);
+                }
+            }
+            return matches.containsAll(mMatchSelector.mChildSelectors);
         }
     }
 
-    /**
-     * Immutable, singly-linked List. Used to keep track of the {@link PartialMatch}es that we
-     * need to update when visiting nodes.
-     */
-    private static class SinglyLinkedList<T> implements Iterable<T> {
+    /** Immutable singly-linked list of matches that is safe for tree traversal. */
+    private static class PartialMatchList implements Iterable<PartialMatch> {
 
-        final Node<T> mHead;
+        final Node mHead;
 
-        /** Constructs an empty list. */
-        public SinglyLinkedList() {
+        PartialMatchList() {
             this(null);
         }
 
-        private SinglyLinkedList(Node<T> head) {
+        private PartialMatchList(Node head) {
             mHead = head;
         }
 
-        /** Returns a new list obtained by prepending {@code data} to {@code rest}. */
-        public static <T> SinglyLinkedList<T> prepend(T data, SinglyLinkedList<T> rest) {
-            return new SinglyLinkedList<>(new Node<>(data, rest.mHead));
+        /** Returns a new list obtained by prepending a match. */
+        PartialMatchList prepend(PartialMatch match) {
+            return new PartialMatchList(new Node(match, mHead));
         }
 
         @Override
-        public Iterator<T> iterator() {
-            return new Iterator<T>() {
-                private Node<T> mNext = mHead;
+        @NonNull
+        public Iterator<PartialMatch> iterator() {
+            return new Iterator<PartialMatch>() {
+                private Node mNext = mHead;
 
                 @Override
                 public boolean hasNext() {
@@ -361,26 +291,21 @@
                 }
 
                 @Override
-                public T next() {
-                    T ret = mNext.data;
-                    mNext = mNext.next;
-                    return ret;
-                }
-
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
+                public PartialMatch next() {
+                    PartialMatch match = mNext.mMatch;
+                    mNext = mNext.mNext;
+                    return match;
                 }
             };
         }
 
-        private static class Node<T> {
-            public final T data;
-            public final Node<T> next;
+        private static class Node {
+            final PartialMatch mMatch;
+            final Node mNext;
 
-            public Node(T d, Node<T> n) {
-                data = d;
-                next = n;
+            Node(PartialMatch match, Node next) {
+                mMatch = match;
+                mNext = next;
             }
         }
     }
diff --git a/testutils/testutils-datastore/build.gradle b/testutils/testutils-datastore/build.gradle
index 0ab9be5..3b3e7ef 100644
--- a/testutils/testutils-datastore/build.gradle
+++ b/testutils/testutils-datastore/build.gradle
@@ -19,6 +19,7 @@
 plugins {
     id("AndroidXPlugin")
 }
+
 androidXMultiplatform {
     jvm {}
     mac()
@@ -33,6 +34,7 @@
                 api(libs.kotlinStdlibCommon)
                 api(libs.kotlinTestCommon)
                 api(libs.kotlinCoroutinesCore)
+                api(libs.kotlinCoroutinesTest)
                 api(libs.okio)
             }
         }
diff --git a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/OkioTestIO.kt b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/OkioTestIO.kt
index afde3af..733d614 100644
--- a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/OkioTestIO.kt
+++ b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/OkioTestIO.kt
@@ -16,6 +16,7 @@
 
 package androidx.datastore
 
+import androidx.datastore.core.InterProcessCoordinator
 import androidx.datastore.core.Storage
 import androidx.datastore.core.okio.OkioStorage
 import kotlin.random.Random
@@ -25,29 +26,54 @@
 import okio.IOException
 import okio.Path.Companion.toPath
 
-class OkioTestIO(dirName: String = "test-dir") : TestIO<OkioPath, IOException>(dirName) {
+open class OkioTestIO(dirName: String = "test-dir") : TestIO<OkioPath, IOException>(dirName) {
     private val fileSystem: FileSystem = FileSystem.SYSTEM
     override fun getStorage(
         serializerConfig: TestingSerializerConfig,
+        coordinatorProducer: () -> InterProcessCoordinator,
         futureFile: () -> TestFile
     ): Storage<Byte> {
-        return OkioStorage(fileSystem, TestingOkioSerializer(serializerConfig)) {
+        return OkioStorage(
+            fileSystem = fileSystem,
+            serializer = TestingOkioSerializer(serializerConfig),
+            coordinatorProducer = { _, _ -> coordinatorProducer() }
+        ) {
             futureFile().getAbsolutePath().toPath()
         }
     }
 
-    override fun tempDir(directoryPath: String?, makeDirs: Boolean): OkioPath {
-        return if (directoryPath != null) {
-            val newPath = if (directoryPath.startsWith("/"))
-                directoryPath.substring(1) else directoryPath
-            val dir = FileSystem.SYSTEM_TEMPORARY_DIRECTORY / randomFileName(dirName) / newPath
-            if (makeDirs) {
-                fileSystem.createDirectories(dir)
+    override fun tempDir(
+        directoryPath: String?,
+        makeDirs: Boolean,
+        parentDir: OkioPath?
+    ): OkioPath {
+        return if (parentDir != null) {
+            if (directoryPath != null) {
+                val newPath = if (directoryPath.startsWith("/"))
+                    directoryPath.substring(1) else directoryPath
+                val dir = parentDir.path / newPath
+                if (makeDirs) {
+                    fileSystem.createDirectories(dir)
+                }
+                OkioPath(fileSystem, dir)
+            } else {
+                OkioPath(fileSystem, parentDir.path / randomFileName(dirName))
             }
-            OkioPath(fileSystem, dir)
         } else {
-            OkioPath(fileSystem, FileSystem.SYSTEM_TEMPORARY_DIRECTORY /
-                randomFileName(dirName))
+            if (directoryPath != null) {
+                val newPath = if (directoryPath.startsWith("/"))
+                    directoryPath.substring(1) else directoryPath
+                val dir = FileSystem.SYSTEM_TEMPORARY_DIRECTORY / randomFileName(dirName) / newPath
+                if (makeDirs) {
+                    fileSystem.createDirectories(dir)
+                }
+                OkioPath(fileSystem, dir)
+            } else {
+                OkioPath(
+                    fileSystem, FileSystem.SYSTEM_TEMPORARY_DIRECTORY /
+                        randomFileName(dirName)
+                )
+            }
         }
     }
 
@@ -82,7 +108,22 @@
     }
 
     override fun delete(): Boolean {
+        if (!fileSystem.exists(path)) {
+            // to be consistent with the TestFile API.
+            return false
+        }
         fileSystem.delete(path)
         return !fileSystem.exists(path)
     }
+
+    override fun exists(): Boolean {
+        return fileSystem.exists(path)
+    }
+
+    override fun createIfNotExists(): Boolean {
+        if (exists()) return false
+        path.parent?.let { fileSystem.createDirectories(it) }
+        fileSystem.write(path, mustCreate = true) { "" }
+        return true
+    }
 }
\ No newline at end of file
diff --git a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestIO.kt b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestIO.kt
index 772f901..bddb036 100644
--- a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestIO.kt
+++ b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestIO.kt
@@ -19,9 +19,12 @@
 import androidx.datastore.core.DataStore
 import androidx.datastore.core.Storage
 import androidx.datastore.core.DataStoreFactory.create
+import androidx.datastore.core.InterProcessCoordinator
 import kotlin.reflect.KClass
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@OptIn(ExperimentalCoroutinesApi::class)
 abstract class TestIO<F : TestFile, IOE : Throwable>(
     protected val dirName: String = "datastore-test-dir"
 ) {
@@ -29,17 +32,24 @@
     fun getStore(
         serializerConfig: TestingSerializerConfig,
         scope: CoroutineScope,
+        coordinatorProducer: () -> InterProcessCoordinator,
         futureFile: () -> TestFile
     ): DataStore<Byte> {
-        return create(getStorage(serializerConfig, futureFile), scope = scope)
+        return create(getStorage(serializerConfig, coordinatorProducer, futureFile), scope = scope)
     }
 
     abstract fun getStorage(
         serializerConfig: TestingSerializerConfig,
+        coordinatorProducer: () -> InterProcessCoordinator,
         futureFile: () -> TestFile = { newTempFile() }
     ): Storage<Byte>
 
-    abstract fun tempDir(directoryPath: String? = null, makeDirs: Boolean = true): F
+    abstract fun tempDir(
+        directoryPath: String? = null,
+        makeDirs: Boolean = true,
+        parentDir: F? = null
+    ): F
+
     abstract fun newTempFile(tempFolder: F = tempDir()): F
 
     abstract fun ioException(message: String): IOE
@@ -50,5 +60,27 @@
 
 abstract class TestFile {
     abstract fun getAbsolutePath(): String
+
+    /**
+     * Deletes the file if it exists.
+     * Will return `false` if the file does not exist or cannot be deleted. (similar to File.delete)
+     */
     abstract fun delete(): Boolean
+
+    /**
+     * Returns true if this file/directory exists.
+     */
+    abstract fun exists(): Boolean
+
+    /**
+     * Creates the file if it doesn't exist.
+     * @return `true` if file didn't exist and gets created and false otherwise.
+     */
+    abstract fun createIfNotExists(): Boolean
+
+    fun deleteIfExists() {
+        if (exists()) {
+            delete()
+        }
+    }
 }
\ No newline at end of file
diff --git a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
index cdfff76..a9565b9 100644
--- a/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
+++ b/testutils/testutils-datastore/src/commonMain/kotlin/androidx/datastore/TestingOkioSerializer.kt
@@ -25,7 +25,7 @@
 import okio.use
 
 class TestingOkioSerializer(
-    val config: TestingSerializerConfig
+    private val config: TestingSerializerConfig
 ) : OkioSerializer<Byte> {
 
     override suspend fun readFrom(source: BufferedSource): Byte {
diff --git a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/FileTestIO.kt b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/FileTestIO.kt
index 3a2c5d0..8345eee 100644
--- a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/FileTestIO.kt
+++ b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/FileTestIO.kt
@@ -17,36 +17,73 @@
 package androidx.datastore
 
 import androidx.datastore.core.FileStorage
+import androidx.datastore.core.InterProcessCoordinator
 import androidx.datastore.core.Storage
 import androidx.datastore.core.TestingSerializer
 import java.io.File
 import java.io.IOException
+import java.util.UUID
 import kotlin.reflect.KClass
 
 class FileTestIO(dirName: String = "test-dir") : TestIO<JavaIOFile, IOException>(dirName) {
 
-    override fun tempDir(directoryPath: String?, makeDirs: Boolean): JavaIOFile {
-        return if (directoryPath != null) {
-            val tempRoot = File.createTempFile("placeholder", "placeholder").parentFile
-            val tempPath = File(tempRoot, directoryPath)
-            if (makeDirs) {
-                tempPath.mkdirs()
+    override fun tempDir(
+        directoryPath: String?,
+        makeDirs: Boolean,
+        parentDir: JavaIOFile?
+    ): JavaIOFile {
+        return if (parentDir != null) {
+            if (directoryPath != null) {
+                val tempPath = File(parentDir.file, directoryPath)
+                if (makeDirs) {
+                    tempPath.mkdirs()
+                }
+                tempPath.toJavaFile()
+            } else {
+                val tempPath = File(parentDir.file, "tempPath")
+                if (makeDirs) {
+                    tempPath.mkdirs()
+                }
+                tempPath.toJavaFile()
             }
-            tempPath.toJavaFile()
         } else {
-            File.createTempFile("temp", "tmp").parentFile.toJavaFile()
+            if (directoryPath != null) {
+                val tempRoot = File.createTempFile("placeholder", "placeholder").parentFile
+                val tempPath = File(tempRoot, directoryPath)
+                if (makeDirs) {
+                    tempPath.mkdirs()
+                }
+                tempPath.toJavaFile()
+            } else {
+                File.createTempFile("temp", "tmp").parentFile!!.toJavaFile()
+            }
         }
     }
 
     override fun newTempFile(tempFolder: JavaIOFile): JavaIOFile {
-        return File.createTempFile("temp", "temp", tempFolder.file).toJavaFile()
+        /**
+         * We need to create a new temp file without creating it so we use a UUID to decide the
+         * file name but also try 100 times in case a collision happens.
+         */
+        // TODO use a consistent naming scheme (e.g. incrementing counter) when b/276983736 is
+        //  fixed. We'll need these TestIO classes to do proper cleanup after themselves to be able
+        //  do that.
+        repeat(100) {
+            val randName = UUID.randomUUID().toString().take(10)
+            val tmpFile = File(tempFolder.file, "temp-$randName-temp")
+            if (!tmpFile.exists()) {
+                return tmpFile.toJavaFile()
+            }
+        }
+        error("Unable to create temp file in $tempFolder")
     }
 
     override fun getStorage(
         serializerConfig: TestingSerializerConfig,
+        coordinatorProducer: () -> InterProcessCoordinator,
         futureFile: () -> TestFile
     ): Storage<Byte> {
-        return FileStorage(TestingSerializer(serializerConfig)) {
+        return FileStorage(TestingSerializer(serializerConfig), { coordinatorProducer() }) {
             (futureFile() as JavaIOFile).file
         }
     }
@@ -71,6 +108,16 @@
     override fun delete(): Boolean {
         return file.delete()
     }
+
+    override fun exists(): Boolean {
+        return file.exists()
+    }
+
+    override fun createIfNotExists(): Boolean {
+        if (exists()) return false
+        file.createNewFile()
+        return true
+    }
 }
 
 fun File.toJavaFile(): JavaIOFile {
diff --git a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.kt b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.kt
index 3027ddd..ab60f1f 100644
--- a/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.kt
+++ b/testutils/testutils-datastore/src/jvmMain/kotlin/androidx/datastore/TestingSerializer.kt
@@ -22,7 +22,7 @@
 import java.io.OutputStream
 
 class TestingSerializer(
-    val config: TestingSerializerConfig = TestingSerializerConfig(),
+    private val config: TestingSerializerConfig = TestingSerializerConfig(),
 ) : Serializer<Byte> {
     override suspend fun readFrom(input: InputStream): Byte {
         // hack to make failReadWithCorruptionException during runtime
diff --git a/testutils/testutils-fonts/build.gradle b/testutils/testutils-fonts/build.gradle
index e2d0377..dffd039 100644
--- a/testutils/testutils-fonts/build.gradle
+++ b/testutils/testutils-fonts/build.gradle
@@ -19,11 +19,7 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-}
-
-androidXMultiplatform {
-    android()
-    desktop()
+    id("kotlin-android")
 }
 
 dependencies {
diff --git a/testutils/testutils-paparazzi/src/main/kotlin/androidx/testutils/paparazzi/ImageDiffer.kt b/testutils/testutils-paparazzi/src/main/kotlin/androidx/testutils/paparazzi/ImageDiffer.kt
index eabb43b..8902cb4 100644
--- a/testutils/testutils-paparazzi/src/main/kotlin/androidx/testutils/paparazzi/ImageDiffer.kt
+++ b/testutils/testutils-paparazzi/src/main/kotlin/androidx/testutils/paparazzi/ImageDiffer.kt
@@ -273,6 +273,12 @@
             windowWidth: Int,
             windowHeight: Int
         ): DoubleArray {
+            if (windowHeight == 1 && windowWidth == 1) {
+                // There is only one item. The variance of a single item would be 0.
+                // Since Bessel's correction is used below, it will return NaN instead of 0.
+                return doubleArrayOf(0.0, 0.0, 0.0)
+            }
+
             var var0 = 0.0
             var var1 = 0.0
             var varBoth = 0.0
@@ -286,9 +292,11 @@
                     varBoth += v0 * v1
                 }
             }
-            var0 /= windowWidth * windowHeight - 1.toDouble()
-            var1 /= windowWidth * windowHeight - 1.toDouble()
-            varBoth /= windowWidth * windowHeight - 1.toDouble()
+            // Using Bessel's correction. Hence, subtracting one.
+            val denominatorWithBesselsCorrection = windowWidth * windowHeight - 1.0
+            var0 /= denominatorWithBesselsCorrection
+            var1 /= denominatorWithBesselsCorrection
+            varBoth /= denominatorWithBesselsCorrection
             return doubleArrayOf(var0, var1, varBoth)
         }
 
@@ -358,4 +366,4 @@
 
         private val SSIM_THRESHOLD: Double = 0.98
     }
-}
\ No newline at end of file
+}
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
index 35b37ea4..368a225 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
@@ -47,7 +47,7 @@
         paint: TextPaint,
         textDir: TextDirectionHeuristic
     ): Metrics? {
-        return if (BuildCompat.isAtLeastT()) {
+        return if (Build.VERSION.SDK_INT >= 33) {
             BoringLayoutFactory33.isBoring(text, paint, textDir)
         } else {
             BoringLayoutFactoryDefault.isBoring(text, paint, textDir)
@@ -124,7 +124,7 @@
      */
     @androidx.annotation.OptIn(markerClass = [BuildCompat.PrereleaseSdkCheck::class])
     fun isFallbackLineSpacingEnabled(layout: BoringLayout): Boolean {
-        return if (BuildCompat.isAtLeastT()) {
+        return if (Build.VERSION.SDK_INT >= 33) {
             BoringLayoutFactory33.isFallbackLineSpacingEnabled(layout)
         } else {
             return false
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
index c1e5fed..88ef45f 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
@@ -211,7 +211,7 @@
         layout: StaticLayout,
         useFallbackLineSpacing: Boolean
     ): Boolean {
-        return if (BuildCompat.isAtLeastT()) {
+        return if (Build.VERSION.SDK_INT >= 33) {
             StaticLayoutFactory33.isFallbackLineSpacingEnabled(layout)
         } else if (Build.VERSION.SDK_INT >= 28) {
             useFallbackLineSpacing
diff --git a/tracing/tracing-ktx/api/1.2.0-beta04.txt b/tracing/tracing-ktx/api/1.2.0-beta04.txt
new file mode 100644
index 0000000..13d99d1
--- /dev/null
+++ b/tracing/tracing-ktx/api/1.2.0-beta04.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> lazyLabel, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static suspend inline <T> Object? traceAsync(String methodName, int cookie, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+    method public static inline <T> T! traceAsync(kotlin.jvm.functions.Function0<java.lang.String> lazyMethodName, kotlin.jvm.functions.Function0<java.lang.Integer> lazyCookie, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/public_plus_experimental_1.2.0-beta04.txt b/tracing/tracing-ktx/api/public_plus_experimental_1.2.0-beta04.txt
new file mode 100644
index 0000000..13d99d1
--- /dev/null
+++ b/tracing/tracing-ktx/api/public_plus_experimental_1.2.0-beta04.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> lazyLabel, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static suspend inline <T> Object? traceAsync(String methodName, int cookie, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+    method public static inline <T> T! traceAsync(kotlin.jvm.functions.Function0<java.lang.String> lazyMethodName, kotlin.jvm.functions.Function0<java.lang.Integer> lazyCookie, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-ktx/api/res-1.2.0-beta04.txt b/tracing/tracing-ktx/api/res-1.2.0-beta04.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tracing/tracing-ktx/api/res-1.2.0-beta04.txt
diff --git a/tracing/tracing-ktx/api/restricted_1.2.0-beta04.txt b/tracing/tracing-ktx/api/restricted_1.2.0-beta04.txt
new file mode 100644
index 0000000..13d99d1
--- /dev/null
+++ b/tracing/tracing-ktx/api/restricted_1.2.0-beta04.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class TraceKt {
+    method public static inline <T> T! trace(String label, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static inline <T> T! trace(kotlin.jvm.functions.Function0<java.lang.String> lazyLabel, kotlin.jvm.functions.Function0<? extends T> block);
+    method public static suspend inline <T> Object? traceAsync(String methodName, int cookie, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super T>,?> block, kotlin.coroutines.Continuation<? super T>);
+    method public static inline <T> T! traceAsync(kotlin.jvm.functions.Function0<java.lang.String> lazyMethodName, kotlin.jvm.functions.Function0<java.lang.Integer> lazyCookie, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
diff --git a/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc b/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
index 8ff0690..3461994 100644
--- a/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
+++ b/tracing/tracing-perfetto-binary/src/main/cpp/tracing_perfetto.cc
@@ -25,7 +25,7 @@
 // Concept of version useful e.g. for human-readable error messages, and stable once released.
 // Does not replace the need for a binary verification mechanism (e.g. checksum check).
 // TODO: populate using CMake
-#define VERSION "1.0.0-alpha14"
+#define VERSION "1.0.0-alpha15"
 
 namespace tracing_perfetto {
     void RegisterWithPerfetto() {
diff --git a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
index c869b03..7c1e230 100644
--- a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
+++ b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/jni/test/PerfettoNativeTest.kt
@@ -30,7 +30,7 @@
         init {
             PerfettoNative.loadLib()
         }
-        const val libraryVersion = "1.0.0-alpha14" // TODO: get using reflection
+        const val libraryVersion = "1.0.0-alpha15" // TODO: get using reflection
     }
 
     @Test
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
index 99808c3..bd7b193 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/jni/PerfettoNative.kt
@@ -25,12 +25,12 @@
 
     // TODO(224510255): load from a file produced at build time
     object Metadata {
-        const val version = "1.0.0-alpha14"
+        const val version = "1.0.0-alpha15"
         val checksums = mapOf(
-            "arm64-v8a" to "8a1bcce00f057c9fb89bf15e82eab868cccbf852008a7aabff1f62bcbbb7f0a5",
-            "armeabi-v7a" to "f3fa9ceefd0de73530a1c113076971d2a33b220801a2d9f0aca82c3a12dcd239",
-            "x86" to "8e76c311e07c8a90efa4f863b5e62e4e9f66f4a271c9abadee2118d82b680a70",
-            "x86_64" to "1f86e16f363f6df6e593b9c83cdd1187e252448c9aed067859c0785339b3f56d",
+            "arm64-v8a" to "4cbe159889b2a9568f779cad114e4ecd1173bb34e503b41727d43d860d0b3313",
+            "armeabi-v7a" to "747e162cf39be138e2335f8e6c8babbddededbdb2cc40370e5d287f1f091ab4a",
+            "x86" to "d26b38905b6182a6d7b8583fcebacbe74374da5242a05bca80263a06d52718db",
+            "x86_64" to "7804c3ab0a5bf42d28dfb7276b087b92d1b81ce2413cc51dda80571e63873554",
         )
     }
 
diff --git a/tracing/tracing/api/1.2.0-beta04.txt b/tracing/tracing/api/1.2.0-beta04.txt
new file mode 100644
index 0000000..c883da2
--- /dev/null
+++ b/tracing/tracing/api/1.2.0-beta04.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static void forceEnableAppTracing();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/public_plus_experimental_1.2.0-beta04.txt b/tracing/tracing/api/public_plus_experimental_1.2.0-beta04.txt
new file mode 100644
index 0000000..c883da2
--- /dev/null
+++ b/tracing/tracing/api/public_plus_experimental_1.2.0-beta04.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static void forceEnableAppTracing();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tracing/tracing/api/res-1.2.0-beta04.txt b/tracing/tracing/api/res-1.2.0-beta04.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tracing/tracing/api/res-1.2.0-beta04.txt
diff --git a/tracing/tracing/api/restricted_1.2.0-beta04.txt b/tracing/tracing/api/restricted_1.2.0-beta04.txt
new file mode 100644
index 0000000..c883da2
--- /dev/null
+++ b/tracing/tracing/api/restricted_1.2.0-beta04.txt
@@ -0,0 +1,15 @@
+// Signature format: 4.0
+package androidx.tracing {
+
+  public final class Trace {
+    method public static void beginAsyncSection(String, int);
+    method public static void beginSection(String);
+    method public static void endAsyncSection(String, int);
+    method public static void endSection();
+    method public static void forceEnableAppTracing();
+    method public static boolean isEnabled();
+    method public static void setCounter(String, int);
+  }
+
+}
+
diff --git a/tv/tv-material/api/public_plus_experimental_current.txt b/tv/tv-material/api/public_plus_experimental_current.txt
index beb7c7f..3f5fc27 100644
--- a/tv/tv-material/api/public_plus_experimental_current.txt
+++ b/tv/tv-material/api/public_plus_experimental_current.txt
@@ -70,10 +70,16 @@
   @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardDefaults {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder);
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardColors compactCardColors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor);
+    method public androidx.compose.ui.graphics.Brush getContainerGradient();
     method public androidx.tv.material3.CardGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
     method public androidx.tv.material3.CardScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale);
     method public androidx.tv.material3.CardShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape);
+    property public final androidx.compose.ui.graphics.Brush ContainerGradient;
+    field public static final float HorizontalImageAspectRatio = 1.7777778f;
     field public static final androidx.tv.material3.CardDefaults INSTANCE;
+    field public static final float SquareImageAspectRatio = 1.0f;
+    field public static final float VerticalImageAspectRatio = 0.6666667f;
   }
 
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardGlow {
@@ -81,6 +87,23 @@
 
   public final class CardKt {
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Card(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, 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> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void CompactCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, 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> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.ui.graphics.Brush scrimBrush, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideClassicCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> image, 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> description, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutColors {
+  }
+
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardLayoutDefaults {
+    method @androidx.compose.runtime.Composable public void ImageCard(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.CardShape shape, optional androidx.tv.material3.CardColors colors, optional androidx.tv.material3.CardScale scale, optional androidx.tv.material3.CardBorder border, optional androidx.tv.material3.CardGlow glow, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.CardLayoutColors contentColor(optional long contentColor, optional long focusedContentColor, optional long pressedContentColor);
+    field public static final androidx.tv.material3.CardLayoutDefaults INSTANCE;
+  }
+
+  public final class CardLayoutKt {
+    method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void StandardCardLayout(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.interaction.MutableInteractionSource,kotlin.Unit> imageCard, 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> description, optional androidx.tv.material3.CardLayoutColors contentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideCardLayout(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.interaction.MutableInteractionSource,kotlin.Unit> imageCard, 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> description, optional androidx.tv.material3.CardLayoutColors contentColor, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class CardScale {
@@ -274,6 +297,32 @@
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class IconButtonDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getLargeButtonSize();
+    method public float getLargeIconSize();
+    method public float getMediumButtonSize();
+    method public float getMediumIconSize();
+    method public float getSmallButtonSize();
+    method public float getSmallIconSize();
+    method public androidx.tv.material3.ButtonGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ButtonScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ButtonShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float LargeButtonSize;
+    property public final float LargeIconSize;
+    property public final float MediumButtonSize;
+    property public final float MediumIconSize;
+    property public final float SmallButtonSize;
+    property public final float SmallIconSize;
+    field public static final androidx.tv.material3.IconButtonDefaults INSTANCE;
+  }
+
+  public final class IconButtonKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void OutlinedIconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.ButtonColors colors, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
+  }
+
   public final class IconKt {
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Icon(androidx.compose.ui.graphics.vector.ImageVector imageVector, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Icon(androidx.compose.ui.graphics.ImageBitmap bitmap, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional long tint);
@@ -342,6 +391,27 @@
     field public static final androidx.tv.material3.OutlinedButtonDefaults INSTANCE;
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class OutlinedIconButtonDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getLargeButtonSize();
+    method public float getLargeIconSize();
+    method public float getMediumButtonSize();
+    method public float getMediumIconSize();
+    method public float getSmallButtonSize();
+    method public float getSmallIconSize();
+    method public androidx.tv.material3.ButtonGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ButtonScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ButtonShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float LargeButtonSize;
+    property public final float LargeIconSize;
+    property public final float MediumButtonSize;
+    property public final float MediumIconSize;
+    property public final float SmallButtonSize;
+    property public final float SmallIconSize;
+    field public static final androidx.tv.material3.OutlinedIconButtonDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Stable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ScaleIndication implements androidx.compose.foundation.Indication {
     ctor public ScaleIndication(float scale);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.interaction.InteractionSource interactionSource);
@@ -482,5 +552,23 @@
     property public final androidx.compose.ui.text.TextStyle titleSmall;
   }
 
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class WideButtonContentColor {
+  }
+
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class WideButtonDefaults {
+    method @androidx.compose.runtime.Composable public void Background(boolean enabled, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ButtonBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.WideButtonContentColor contentColor(optional long color, optional long focusedColor, optional long pressedColor, optional long disabledColor);
+    method public androidx.tv.material3.ButtonGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ButtonScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ButtonShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    field public static final androidx.tv.material3.WideButtonDefaults INSTANCE;
+  }
+
+  public final class WideButtonKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void WideButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? subtitle, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> background, optional androidx.tv.material3.ButtonScale scale, optional androidx.tv.material3.ButtonGlow glow, optional androidx.tv.material3.ButtonShape shape, optional androidx.tv.material3.WideButtonContentColor contentColor, optional float tonalElevation, optional androidx.tv.material3.ButtonBorder border, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
+  }
+
 }
 
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutScreenshotTest.kt
new file mode 100644
index 0000000..5c6a7ff
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutScreenshotTest.kt
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performSemanticsAction
+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 org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class CardLayoutScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    private val boxSizeModifier = Modifier.size(220.dp, 180.dp)
+    private val standardCardLayoutSizeModifier = Modifier.size(150.dp, 120.dp)
+    private val wideCardLayoutSizeModifier = Modifier.size(180.dp, 100.dp)
+
+    @Test
+    fun standardCardLayout_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardLayoutWrapperTag),
+                    contentAlignment = Alignment.Center
+                ) {
+                    StandardCardLayout(
+                        modifier = standardCardLayoutSizeModifier,
+                        imageCard = { interactionSource ->
+                            CardLayoutDefaults.ImageCard(
+                                onClick = { },
+                                interactionSource = interactionSource
+                            ) {
+                                SampleImage(
+                                    Modifier
+                                        .fillMaxWidth()
+                                        .height(80.dp)
+                                )
+                            }
+                        },
+                        title = { Text("Standard Card") }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("standardCardLayout_lightTheme")
+    }
+
+    @Test
+    fun standardCardLayout_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardLayoutWrapperTag),
+                    contentAlignment = Alignment.Center
+                ) {
+                    StandardCardLayout(
+                        modifier = standardCardLayoutSizeModifier,
+                        imageCard = { interactionSource ->
+                            CardLayoutDefaults.ImageCard(
+                                onClick = { },
+                                interactionSource = interactionSource
+                            ) {
+                                SampleImage(
+                                    Modifier
+                                        .fillMaxWidth()
+                                        .height(80.dp)
+                                )
+                            }
+                        },
+                        title = { Text("Standard Card") }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("standardCardLayout_darkTheme")
+    }
+
+    @Test
+    fun standardCardLayout_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier
+                    .testTag(CardLayoutWrapperTag)
+                    .semantics(mergeDescendants = true) {},
+                contentAlignment = Alignment.Center
+            ) {
+                StandardCardLayout(
+                    modifier = standardCardLayoutSizeModifier,
+                    imageCard = { interactionSource ->
+                        CardLayoutDefaults.ImageCard(
+                            onClick = { },
+                            interactionSource = interactionSource
+                        ) {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxWidth()
+                                    .height(80.dp)
+                            )
+                        }
+                    },
+                    title = { Text("Standard Card", Modifier.padding(top = 5.dp)) }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(CardLayoutWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("standardCardLayout_focused")
+    }
+
+    @Test
+    fun wideCardLayout_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardLayoutWrapperTag),
+                    contentAlignment = Alignment.Center
+                ) {
+                    WideCardLayout(
+                        modifier = wideCardLayoutSizeModifier,
+                        imageCard = { interactionSource ->
+                            CardLayoutDefaults.ImageCard(
+                                onClick = { },
+                                interactionSource = interactionSource
+                            ) {
+                                SampleImage(
+                                    Modifier
+                                        .fillMaxHeight()
+                                        .width(90.dp)
+                                )
+                            }
+                        },
+                        title = { Text("Wide Card", Modifier.padding(start = 8.dp)) },
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("wideCardLayout_lightTheme")
+    }
+
+    @Test
+    fun wideCardLayout_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardLayoutWrapperTag),
+                    contentAlignment = Alignment.Center
+                ) {
+                    WideCardLayout(
+                        modifier = wideCardLayoutSizeModifier,
+                        imageCard = { interactionSource ->
+                            CardLayoutDefaults.ImageCard(
+                                onClick = { },
+                                interactionSource = interactionSource
+                            ) {
+                                SampleImage(
+                                    Modifier
+                                        .fillMaxHeight()
+                                        .width(90.dp)
+                                )
+                            }
+                        },
+                        title = { Text("Wide Card", Modifier.padding(start = 8.dp)) },
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("wideCardLayout_darkTheme")
+    }
+
+    @Test
+    fun wideCardLayout_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier
+                    .testTag(CardLayoutWrapperTag)
+                    .semantics(mergeDescendants = true) {},
+                contentAlignment = Alignment.Center
+            ) {
+                WideCardLayout(
+                    modifier = wideCardLayoutSizeModifier,
+                    imageCard = { interactionSource ->
+                        CardLayoutDefaults.ImageCard(
+                            onClick = { },
+                            interactionSource = interactionSource
+                        ) {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxHeight()
+                                    .width(90.dp)
+                            )
+                        }
+                    },
+                    title = { Text("Wide Card", Modifier.padding(start = 8.dp)) },
+                )
+            }
+        }
+
+        rule.onNodeWithTag(CardLayoutWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("wideCardLayout_focused")
+    }
+
+    @Composable
+    fun SampleImage(modifier: Modifier = Modifier) {
+        Box(
+            modifier = modifier
+                .background(Color.Blue)
+        )
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(CardLayoutWrapperTag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+}
+
+private const val CardLayoutWrapperTag = "card_layout_wrapper"
\ No newline at end of file
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutTest.kt
new file mode 100644
index 0000000..f180509
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardLayoutTest.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertTextEquals
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(
+    ExperimentalTestApi::class,
+    ExperimentalComposeUiApi::class,
+    ExperimentalTvMaterial3Api::class
+)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class CardLayoutTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun standardCardLayout_semantics() {
+        val count = mutableStateOf(0)
+        rule.setContent {
+            StandardCardLayout(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(StandardCardLayoutTag),
+                imageCard = { interactionSource ->
+                    CardLayoutDefaults.ImageCard(
+                        onClick = { count.value += 1 },
+                        interactionSource = interactionSource
+                    ) { SampleImage() }
+                },
+                title = { Text("${count.value}") }
+            )
+        }
+
+        rule.onNodeWithTag(StandardCardLayoutTag)
+            .onChild()
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .assertIsEnabled()
+
+        rule.onNodeWithTag(StandardCardLayoutTag)
+            .assertTextEquals("0")
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assertTextEquals("1")
+    }
+
+    @Test
+    fun standardCardLayout_clickAction() {
+        val count = mutableStateOf(0f)
+        rule.setContent {
+            StandardCardLayout(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(StandardCardLayoutTag),
+                imageCard = { interactionSource ->
+                    CardLayoutDefaults.ImageCard(
+                        onClick = { count.value += 1 },
+                        interactionSource = interactionSource
+                    ) { SampleImage() }
+                },
+                title = { Text("${count.value}") }
+            )
+        }
+
+        rule.onNodeWithTag(StandardCardLayoutTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(1)
+
+        rule.onNodeWithTag(StandardCardLayoutTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(3)
+    }
+
+    @Test
+    fun wideCardLayout_semantics() {
+        val count = mutableStateOf(0)
+        rule.setContent {
+            WideCardLayout(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(WideCardLayoutTag),
+                imageCard = { interactionSource ->
+                    CardLayoutDefaults.ImageCard(
+                        onClick = { count.value += 1 },
+                        interactionSource = interactionSource
+                    ) { SampleImage() }
+                },
+                title = { Text("${count.value}") }
+            )
+        }
+
+        rule.onNodeWithTag(WideCardLayoutTag)
+            .onChild()
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .assertIsEnabled()
+
+        rule.onNodeWithTag(WideCardLayoutTag)
+            .assertTextEquals("0")
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assertTextEquals("1")
+    }
+
+    @Test
+    fun wideCardLayout_clickAction() {
+        val count = mutableStateOf(0f)
+        rule.setContent {
+            WideCardLayout(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(WideCardLayoutTag),
+                imageCard = { interactionSource ->
+                    CardLayoutDefaults.ImageCard(
+                        onClick = { count.value += 1 },
+                        interactionSource = interactionSource
+                    ) { SampleImage() }
+                },
+                title = { Text("${count.value}") }
+            )
+        }
+
+        rule.onNodeWithTag(WideCardLayoutTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(1)
+
+        rule.onNodeWithTag(WideCardLayoutTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(3)
+    }
+
+    @Composable
+    fun SampleImage() {
+        Box(
+            Modifier
+                .size(180.dp, 150.dp)
+                .testTag(SampleImageTag)
+        )
+    }
+}
+
+private const val StandardCardLayoutTag = "standard-card-layout"
+private const val WideCardLayoutTag = "wide-card-layout"
+
+private const val SampleImageTag = "sample-image"
\ No newline at end of file
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardScreenshotTest.kt
new file mode 100644
index 0000000..f613158
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardScreenshotTest.kt
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxHeight
+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.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment.Companion.Center
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performSemanticsAction
+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 org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class CardScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    private val boxSizeModifier = Modifier.size(220.dp, 180.dp)
+    private val verticalCardSizeModifier = Modifier.size(150.dp, 120.dp)
+    private val horizontalCardSizeModifier = Modifier.size(180.dp, 100.dp)
+
+    @Test
+    fun card_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    Card(
+                        modifier = verticalCardSizeModifier,
+                        onClick = { }
+                    ) {
+                        Box(Modifier.fillMaxSize()) {
+                            Text("Card", Modifier.align(Center))
+                        }
+                    }
+                }
+            }
+        }
+
+        assertAgainstGolden("card_lightTheme")
+    }
+
+    @Test
+    fun card_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    Card(
+                        modifier = verticalCardSizeModifier,
+                        onClick = { }
+                    ) {
+                        Box(Modifier.fillMaxSize()) {
+                            Text("Card", Modifier.align(Center))
+                        }
+                    }
+                }
+            }
+        }
+
+        assertAgainstGolden("card_darkTheme")
+    }
+
+    @Test
+    fun card_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier.testTag(CardWrapperTag),
+                contentAlignment = Center
+            ) {
+                Card(
+                    modifier = verticalCardSizeModifier,
+                    onClick = { }
+                ) {
+                    Box(Modifier.fillMaxSize()) {
+                        Text("Card", Modifier.align(Center))
+                    }
+                }
+            }
+        }
+
+        rule.onNodeWithTag(CardWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("card_focused")
+    }
+
+    @Test
+    fun classicCard_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    ClassicCard(
+                        modifier = verticalCardSizeModifier,
+                        image = {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxWidth()
+                                    .height(80.dp)
+                            )
+                        },
+                        title = { Text("Classic Card") },
+                        contentPadding = PaddingValues(8.dp),
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("classicCard_lightTheme")
+    }
+
+    @Test
+    fun classicCard_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    ClassicCard(
+                        modifier = verticalCardSizeModifier,
+                        image = {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxWidth()
+                                    .height(80.dp)
+                            )
+                        },
+                        title = { Text("Classic Card") },
+                        contentPadding = PaddingValues(8.dp),
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("classicCard_darkTheme")
+    }
+
+    @Test
+    fun classicCard_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier.testTag(CardWrapperTag),
+                contentAlignment = Center
+            ) {
+                ClassicCard(
+                    modifier = verticalCardSizeModifier,
+                    image = {
+                        SampleImage(
+                            Modifier
+                                .fillMaxWidth()
+                                .height(80.dp)
+                        )
+                    },
+                    title = { Text("Classic Card") },
+                    contentPadding = PaddingValues(8.dp),
+                    onClick = { }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(CardWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("classicCard_focused")
+    }
+
+    @Test
+    fun compactCard_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    CompactCard(
+                        modifier = verticalCardSizeModifier,
+                        image = { SampleImage(Modifier.fillMaxSize()) },
+                        title = { Text("Compact Card", Modifier.padding(8.dp)) },
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("compactCard_lightTheme")
+    }
+
+    @Test
+    fun compactCard_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    CompactCard(
+                        modifier = verticalCardSizeModifier,
+                        image = { SampleImage(Modifier.fillMaxSize()) },
+                        title = { Text("Compact Card", Modifier.padding(8.dp)) },
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("compactCard_darkTheme")
+    }
+
+    @Test
+    fun compactCard_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier.testTag(CardWrapperTag),
+                contentAlignment = Center
+            ) {
+                CompactCard(
+                    modifier = verticalCardSizeModifier,
+                    image = { SampleImage(Modifier.fillMaxSize()) },
+                    title = { Text("Compact Card", Modifier.padding(8.dp)) },
+                    onClick = { }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(CardWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("compactCard_focused")
+    }
+
+    @Test
+    fun wideClassicCard_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    WideClassicCard(
+                        modifier = horizontalCardSizeModifier,
+                        image = {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxHeight()
+                                    .width(80.dp)
+                            )
+                        },
+                        title = { Text("Wide Classic Card", Modifier.padding(start = 8.dp)) },
+                        contentPadding = PaddingValues(8.dp),
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("wideClassicCard_lightTheme")
+    }
+
+    @Test
+    fun wideClassicCard_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(
+                    modifier = boxSizeModifier.testTag(CardWrapperTag),
+                    contentAlignment = Center
+                ) {
+                    WideClassicCard(
+                        modifier = horizontalCardSizeModifier,
+                        image = {
+                            SampleImage(
+                                Modifier
+                                    .fillMaxHeight()
+                                    .width(80.dp)
+                            )
+                        },
+                        title = { Text("Wide Classic Card", Modifier.padding(start = 8.dp)) },
+                        contentPadding = PaddingValues(8.dp),
+                        onClick = { }
+                    )
+                }
+            }
+        }
+
+        assertAgainstGolden("wideClassicCard_darkTheme")
+    }
+
+    @Test
+    fun wideClassicCard_focused() {
+        rule.setContent {
+            Box(
+                modifier = boxSizeModifier.testTag(CardWrapperTag),
+                contentAlignment = Center
+            ) {
+                WideClassicCard(
+                    modifier = horizontalCardSizeModifier,
+                    image = {
+                        SampleImage(
+                            Modifier
+                                .fillMaxHeight()
+                                .width(80.dp)
+                        )
+                    },
+                    title = { Text("Wide Classic Card", Modifier.padding(start = 8.dp)) },
+                    contentPadding = PaddingValues(8.dp),
+                    onClick = { }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(CardWrapperTag)
+            .onChild()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.waitForIdle()
+
+        assertAgainstGolden("wideClassicCard_focused")
+    }
+
+    @Composable
+    fun SampleImage(modifier: Modifier = Modifier) {
+        Box(
+            modifier = modifier
+                .background(Color.Blue)
+        )
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(CardWrapperTag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+}
+
+private const val CardWrapperTag = "card_wrapper"
\ No newline at end of file
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
index d4437c7..68be7c4 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
@@ -23,11 +23,14 @@
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.CutCornerShape
+import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.testutils.assertIsEqualTo
 import androidx.compose.testutils.assertShape
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -44,6 +47,7 @@
 import androidx.compose.ui.test.assertIsEnabled
 import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performKeyInput
@@ -51,7 +55,7 @@
 import androidx.compose.ui.test.pressKey
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
+import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth
 import kotlinx.coroutines.CoroutineScope
@@ -65,7 +69,7 @@
     ExperimentalComposeUiApi::class,
     ExperimentalTvMaterial3Api::class
 )
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4::class)
 class CardTest {
     @get:Rule
@@ -82,7 +86,7 @@
                 Card(
                     modifier = Modifier
                         .semantics(mergeDescendants = true) {}
-                        .testTag("card"),
+                        .testTag(CardTag),
                     shape = CardDefaults.shape(shape = shape),
                     colors = CardDefaults.colors(containerColor = cardColor),
                     onClick = {}
@@ -93,7 +97,7 @@
         }
 
         rule
-            .onNodeWithTag("card")
+            .onNodeWithTag(CardTag)
             .captureToImage()
             .assertShape(
                 density = rule.density,
@@ -109,14 +113,15 @@
         val count = mutableStateOf(0)
         rule.setContent {
             Card(
-                modifier = Modifier.testTag("card"),
+                modifier = Modifier.testTag(CardTag),
                 onClick = { count.value += 1 },
             ) {
                 Text("${count.value}")
                 Spacer(Modifier.size(30.dp))
             }
         }
-        rule.onNodeWithTag("card")
+
+        rule.onNodeWithTag(CardTag)
             .assertHasClickAction()
             .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
             .performSemanticsAction(SemanticsActions.RequestFocus)
@@ -131,7 +136,7 @@
         val count = mutableStateOf(0f)
         rule.setContent {
             Card(
-                modifier = Modifier.testTag("card"),
+                modifier = Modifier.testTag(CardTag),
                 onClick = { count.value += 1 },
             ) {
                 Text("${count.value}")
@@ -139,12 +144,12 @@
             }
         }
 
-        rule.onNodeWithTag("card")
+        rule.onNodeWithTag(CardTag)
             .performSemanticsAction(SemanticsActions.RequestFocus)
             .performKeyInput { pressKey(Key.DirectionCenter) }
         Truth.assertThat(count.value).isEqualTo(1)
 
-        rule.onNodeWithTag("card")
+        rule.onNodeWithTag(CardTag)
             .performSemanticsAction(SemanticsActions.RequestFocus)
             .performKeyInput { pressKey(Key.DirectionCenter) }
             .performKeyInput { pressKey(Key.DirectionCenter) }
@@ -161,7 +166,7 @@
             scope = rememberCoroutineScope()
             Card(
                 onClick = {},
-                modifier = Modifier.testTag("card"),
+                modifier = Modifier.testTag(CardTag),
                 interactionSource = interactionSource
             ) {
                 Spacer(Modifier.size(30.dp))
@@ -174,14 +179,14 @@
 
         rule.runOnIdle { Truth.assertThat(interactions).isEmpty() }
 
-        rule.onNodeWithTag("card").performSemanticsAction(SemanticsActions.RequestFocus)
+        rule.onNodeWithTag(CardTag).performSemanticsAction(SemanticsActions.RequestFocus)
 
         rule.runOnIdle {
             Truth.assertThat(interactions).hasSize(1)
             Truth.assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
         }
 
-        rule.onNodeWithTag("card").performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.onNodeWithTag(CardTag).performKeyInput { pressKey(Key.DirectionCenter) }
 
         rule.runOnIdle {
             Truth.assertThat(interactions).hasSize(3)
@@ -190,4 +195,284 @@
             Truth.assertThat(interactions[2]).isInstanceOf(PressInteraction.Release::class.java)
         }
     }
-}
\ No newline at end of file
+
+    @Test
+    fun classicCard_semantics() {
+        val count = mutableStateOf(0)
+        rule.setContent {
+            ClassicCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(ClassicCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(ClassicCardTag)
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .assertIsEnabled()
+            .assertTextEquals("0")
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assertTextEquals("1")
+    }
+
+    @Test
+    fun classicCard_clickAction() {
+        val count = mutableStateOf(0f)
+        rule.setContent {
+            ClassicCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(ClassicCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(ClassicCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(1)
+
+        rule.onNodeWithTag(ClassicCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(3)
+    }
+
+    @Test
+    fun classicCard_contentPadding() {
+        val contentPadding = PaddingValues(8.dp, 10.dp, 12.dp, 14.dp)
+        val cardTitleTag = "classic_card_title"
+
+        rule.setContent {
+            ClassicCard(
+                modifier = Modifier.testTag(ClassicCardTag),
+                image = { SampleImage() },
+                title = {
+                    Text(
+                        text = "Classic Card",
+                        modifier = Modifier.testTag(cardTitleTag)
+                    )
+                },
+                onClick = {},
+                contentPadding = contentPadding
+            )
+        }
+
+        val cardBounds = rule
+            .onNodeWithTag(ClassicCardTag)
+            .getUnclippedBoundsInRoot()
+
+        val imageBounds = rule
+            .onNodeWithTag(SampleImageTag, true)
+            .getUnclippedBoundsInRoot()
+
+        val titleBounds = rule
+            .onNodeWithTag(cardTitleTag, true)
+            .getUnclippedBoundsInRoot()
+
+        // Check top padding
+        (imageBounds.top - cardBounds.top).assertIsEqualTo(
+            10.dp,
+            "padding between top of the image and top of the card."
+        )
+
+        // Check bottom padding
+        (cardBounds.bottom - titleBounds.bottom).assertIsEqualTo(
+            14.dp,
+            "padding between bottom of the text and bottom of the card."
+        )
+
+        // Check start padding
+        (imageBounds.left - cardBounds.left).assertIsEqualTo(
+            8.dp,
+            "padding between left of the image and left of the card."
+        )
+
+        // Check end padding
+        (cardBounds.right - imageBounds.right).assertIsEqualTo(
+            12.dp,
+            "padding between right of the text and right of the card."
+        )
+    }
+
+    @Test
+    fun compactCard_semantics() {
+        val count = mutableStateOf(0)
+        rule.setContent {
+            CompactCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(CompactCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(CompactCardTag)
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .assertIsEnabled()
+            .assertTextEquals("0")
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assertTextEquals("1")
+    }
+
+    @Test
+    fun compactCard_clickAction() {
+        val count = mutableStateOf(0f)
+        rule.setContent {
+            CompactCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(CompactCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(CompactCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(1)
+
+        rule.onNodeWithTag(CompactCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(3)
+    }
+
+    @Test
+    fun wideClassicCard_semantics() {
+        val count = mutableStateOf(0)
+        rule.setContent {
+            WideClassicCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(WideClassicCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(WideClassicCardTag)
+            .assertHasClickAction()
+            .assert(SemanticsMatcher.keyNotDefined(SemanticsProperties.Role))
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .assertIsEnabled()
+            .assertTextEquals("0")
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .assertTextEquals("1")
+    }
+
+    @Test
+    fun wideClassicCard_clickAction() {
+        val count = mutableStateOf(0f)
+        rule.setContent {
+            WideClassicCard(
+                modifier = Modifier
+                    .semantics(mergeDescendants = true) {}
+                    .testTag(WideClassicCardTag),
+                image = { SampleImage() },
+                title = { Text("${count.value}") },
+                onClick = { count.value += 1 }
+            )
+        }
+
+        rule.onNodeWithTag(WideClassicCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(1)
+
+        rule.onNodeWithTag(WideClassicCardTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        Truth.assertThat(count.value).isEqualTo(3)
+    }
+
+    @Test
+    fun wideClassicCard_contentPadding() {
+        val contentPadding = PaddingValues(8.dp, 10.dp, 12.dp, 14.dp)
+        val cardTitleTag = "wide_classic_card_title"
+
+        rule.setContent {
+            WideClassicCard(
+                modifier = Modifier.testTag(WideClassicCardTag),
+                image = { SampleImage() },
+                title = {
+                    Text(
+                        text = "Wide Classic Card",
+                        modifier = Modifier.testTag(cardTitleTag)
+                    )
+                },
+                onClick = {},
+                contentPadding = contentPadding
+            )
+        }
+
+        val cardBounds = rule
+            .onNodeWithTag(WideClassicCardTag)
+            .getUnclippedBoundsInRoot()
+
+        val imageBounds = rule
+            .onNodeWithTag(SampleImageTag, true)
+            .getUnclippedBoundsInRoot()
+
+        val titleBounds = rule
+            .onNodeWithTag(cardTitleTag, true)
+            .getUnclippedBoundsInRoot()
+
+        // Check top padding
+        (imageBounds.top - cardBounds.top).assertIsEqualTo(
+            10.dp,
+            "padding between top of the image and top of the card."
+        )
+
+        // Check bottom padding
+        (cardBounds.bottom - imageBounds.bottom).assertIsEqualTo(
+            14.dp,
+            "padding between bottom of the text and bottom of the card."
+        )
+
+        // Check start padding
+        (imageBounds.left - cardBounds.left).assertIsEqualTo(
+            8.dp,
+            "padding between left of the image and left of the card."
+        )
+
+        // Check end padding
+        (cardBounds.right - titleBounds.right).assertIsEqualTo(
+            12.dp,
+            "padding between right of the text and right of the card."
+        )
+    }
+
+    @Composable
+    fun SampleImage() {
+        Box(
+            Modifier
+                .size(180.dp, 150.dp)
+                .testTag(SampleImageTag)
+        )
+    }
+}
+
+private const val CardTag = "card"
+private const val CompactCardTag = "compact-card"
+private const val ClassicCardTag = "classic-card"
+private const val WideClassicCardTag = "wide-classic-card"
+
+private const val SampleImageTag = "sample-image"
\ No newline at end of file
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonScreenshotTest.kt
new file mode 100644
index 0000000..9cf007a
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonScreenshotTest.kt
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.material.icons.outlined.FavoriteBorder
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.InputMode
+import androidx.compose.ui.input.InputModeManager
+import androidx.compose.ui.platform.LocalInputModeManager
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.hasClickAction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performMouseInput
+import androidx.compose.ui.test.performTouchInput
+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 org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@OptIn(ExperimentalTestApi::class, ExperimentalTvMaterial3Api::class)
+class IconButtonScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    private val wrap = Modifier.wrapContentSize(Alignment.TopStart)
+    private val wrapperTestTag = "iconButtonWrapper"
+
+    @Test
+    fun iconButton_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("iconButton_lightTheme")
+    }
+
+    @Test
+    fun iconButton_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(
+                            Icons.Filled.Favorite,
+                            contentDescription = "Localized description"
+                        )
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("iconButton_darkTheme")
+    }
+
+    @Test
+    fun iconButton_lightTheme_disabled() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }, enabled = false) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("iconButton_lightTheme_disabled")
+    }
+
+    @Test
+    fun iconButton_darkTheme_disabled() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }, enabled = false) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("iconButton_darkTheme_disabled")
+    }
+
+    @Test
+    fun iconButton_lightTheme_pressed() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+
+        rule.mainClock.autoAdvance = false
+        rule.onNode(hasClickAction())
+            .performTouchInput { down(center) }
+
+        rule.mainClock.advanceTimeByFrame()
+        rule.waitForIdle() // Wait for measure
+        rule.mainClock.advanceTimeBy(milliseconds = 200)
+
+        assertAgainstGolden("iconButton_lightTheme_pressed")
+    }
+
+    @Test
+    fun iconButton_darkTheme_pressed() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+
+        rule.mainClock.autoAdvance = false
+        rule.onNode(hasClickAction())
+            .performTouchInput { down(center) }
+
+        rule.mainClock.advanceTimeByFrame()
+        rule.waitForIdle() // Wait for measure
+        rule.mainClock.advanceTimeBy(milliseconds = 200)
+
+        assertAgainstGolden("iconButton_darkTheme_pressed")
+    }
+
+    @Test
+    fun iconButton_lightTheme_hovered() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+        rule.onNodeWithTag(wrapperTestTag).performMouseInput {
+            enter(center)
+        }
+
+        assertAgainstGolden("iconButton_lightTheme_hovered")
+    }
+
+    @Test
+    fun iconButton_darkTheme_hovered() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+        rule.onNodeWithTag(wrapperTestTag).performMouseInput {
+            enter(center)
+        }
+
+        assertAgainstGolden("iconButton_darkTheme_hovered")
+    }
+
+    @Test
+    fun iconButton_lightTheme_focused() {
+        val focusRequester = FocusRequester()
+        var localInputModeManager: InputModeManager? = null
+
+        rule.setContent {
+            LightMaterialTheme {
+                localInputModeManager = LocalInputModeManager.current
+                Box(Modifier.sizeIn(minWidth = 52.dp, minHeight = 52.dp).testTag(wrapperTestTag)) {
+                    IconButton(
+                        onClick = { /* doSomething() */ },
+                        modifier = Modifier
+                            .align(Alignment.Center)
+                            .focusRequester(focusRequester)
+                    ) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            localInputModeManager!!.requestInputMode(InputMode.Keyboard)
+            focusRequester.requestFocus()
+        }
+
+        assertAgainstGolden("iconButton_lightTheme_focused")
+    }
+
+    @Test
+    fun iconButton_darkTheme_focused() {
+        val focusRequester = FocusRequester()
+        var localInputModeManager: InputModeManager? = null
+
+        rule.setContent {
+            DarkMaterialTheme {
+                localInputModeManager = LocalInputModeManager.current
+                Box(Modifier.sizeIn(minWidth = 52.dp, minHeight = 52.dp).testTag(wrapperTestTag)) {
+                    IconButton(
+                        onClick = { /* doSomething() */ },
+                        modifier = Modifier
+                            .align(Alignment.Center)
+                            .focusRequester(focusRequester)
+                    ) {
+                        Icon(Icons.Filled.Favorite, contentDescription = "Localized description")
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            localInputModeManager!!.requestInputMode(InputMode.Keyboard)
+            focusRequester.requestFocus()
+        }
+
+        assertAgainstGolden("iconButton_darkTheme_focused")
+    }
+
+    @Test
+    fun iconButton_largeContentClipped() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    IconButton(onClick = { /* doSomething() */ }) {
+                        Box(
+                            Modifier
+                                .size(100.dp)
+                                .background(Color.Blue))
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("iconButton_largeContentClipped")
+    }
+
+    @Test
+    fun outlinedIconButton_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    OutlinedIconButton(onClick = { /* doSomething() */ }) {
+                        Icon(
+                            Icons.Outlined.FavoriteBorder,
+                            contentDescription = "Localized description"
+                        )
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("outlinedIconButton_lightTheme")
+    }
+
+    @Test
+    fun outlinedIconButton_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    OutlinedIconButton(onClick = { /* doSomething() */ }) {
+                        Icon(
+                            Icons.Outlined.FavoriteBorder,
+                            contentDescription = "Localized description"
+                        )
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("outlinedIconButton_darkTheme")
+    }
+
+    @Test
+    fun outlinedIconButton_lightTheme_disabled() {
+        rule.setContent {
+            LightMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    OutlinedIconButton(onClick = { /* doSomething() */ }, enabled = false) {
+                        Icon(
+                            Icons.Outlined.FavoriteBorder,
+                            contentDescription = "Localized description"
+                        )
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("outlinedIconButton_lightTheme_disabled")
+    }
+
+    @Test
+    fun outlinedIconButton_darkTheme_disabled() {
+        rule.setContent {
+            DarkMaterialTheme {
+                Box(wrap.testTag(wrapperTestTag)) {
+                    OutlinedIconButton(onClick = { /* doSomething() */ }, enabled = false) {
+                        Icon(
+                            Icons.Outlined.FavoriteBorder,
+                            contentDescription = "Localized description"
+                        )
+                    }
+                }
+            }
+        }
+        assertAgainstGolden("outlinedIconButton_darkTheme_disabled")
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(wrapperTestTag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt
new file mode 100644
index 0000000..8e1fdc1
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonTest.kt
@@ -0,0 +1,982 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsEqualTo
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(
+    ExperimentalTestApi::class,
+    ExperimentalComposeUiApi::class,
+    ExperimentalTvMaterial3Api::class
+)
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class IconButtonTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun filledIconButton_DefaultSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assertWidthIsEqualTo(40.dp)
+            .assertHeightIsEqualTo(40.dp)
+    }
+
+    @Test
+    fun filledIconButton_SmallSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(IconButtonDefaults.SmallButtonSize)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assertWidthIsEqualTo(28.dp)
+            .assertHeightIsEqualTo(28.dp)
+    }
+
+    @Test
+    fun filledIconButton_MediumSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(IconButtonDefaults.MediumButtonSize)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assertWidthIsEqualTo(40.dp)
+            .assertHeightIsEqualTo(40.dp)
+    }
+
+    @Test
+    fun filledIconButton_LargeSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(IconButtonDefaults.LargeButtonSize)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assertWidthIsEqualTo(56.dp)
+            .assertHeightIsEqualTo(56.dp)
+    }
+
+    @Test
+    fun filledIconButton_CustomSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(64.dp)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assertWidthIsEqualTo(64.dp)
+            .assertHeightIsEqualTo(64.dp)
+    }
+
+    @Test
+    fun filledIconButton_size_withoutMinimumTouchTarget() {
+        val width = 24.dp
+        val height = 24.dp
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .testTag(FilledIconButtonTag)
+                    .size(width, height),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(FilledIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag, useUnmergedTree = true)
+            .assertWidthIsEqualTo(width)
+            .assertHeightIsEqualTo(height)
+    }
+
+    @Test
+    fun filledIconButton_defaultSemantics() {
+        rule.setContent {
+            Box {
+                IconButton(modifier = Modifier.testTag(FilledIconButtonTag), onClick = {}) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun filledIconButton_disabledSemantics() {
+        rule.setContent {
+            Box {
+                IconButton(
+                    modifier = Modifier.testTag(FilledIconButtonTag),
+                    onClick = {},
+                    enabled = false
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun filledIconButton_findByTagAndClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            Box {
+                IconButton(
+                    modifier = Modifier.testTag(FilledIconButtonTag),
+                    onClick = onClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+        rule.onNodeWithTag(FilledIconButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun filledIconButton_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                IconButton(
+                    modifier = Modifier.testTag(FilledIconButtonTag),
+                    onClick = { enabled = false },
+                    enabled = enabled
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+        rule.onNodeWithTag(FilledIconButtonTag)
+            // Confirm the button starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun filledIconButton_clickIsIndependentBetweenButtons() {
+        var addButtonCounter = 0
+        val addButtonOnClick: () -> Unit = { ++addButtonCounter }
+        val addButtonTag = "AddButton"
+
+        var phoneButtonCounter = 0
+        val phoneButtonOnClick: () -> Unit = { ++phoneButtonCounter }
+        val phoneButtonTag = "PhoneButton"
+
+        rule.setContent {
+            Column {
+                IconButton(
+                    modifier = Modifier.testTag(addButtonTag),
+                    onClick = addButtonOnClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+                IconButton(
+                    modifier = Modifier.testTag(phoneButtonTag),
+                    onClick = phoneButtonOnClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(IconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(addButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(addButtonCounter).isEqualTo(1)
+            Truth.assertThat(phoneButtonCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(phoneButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(addButtonCounter).isEqualTo(1)
+            Truth.assertThat(phoneButtonCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun filledIconButton_buttonPositioningSmallSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(IconButtonDefaults.SmallButtonSize)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(IconButtonDefaults.SmallIconSize)
+                        .testTag(FilledIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(FilledIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(FilledIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            6.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            6.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            6.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            6.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun filledIconButton_buttonPositioningDefaultOrMediumSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier.testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(IconButtonDefaults.MediumIconSize)
+                        .testTag(FilledIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(FilledIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(FilledIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            10.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            10.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            10.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            10.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun filledIconButton_buttonPositioningLargeSize() {
+        rule.setContent {
+            IconButton(
+                modifier = Modifier
+                    .size(IconButtonDefaults.LargeButtonSize)
+                    .testTag(FilledIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(IconButtonDefaults.LargeIconSize)
+                        .testTag(FilledIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(FilledIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(FilledIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            14.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            14.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            14.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            14.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun filledIconButton_defaultSize_materialIconSize_iconPositioning() {
+        val diameter = IconButtonDefaults.MediumIconSize
+        rule.setContent {
+            Box {
+                IconButton(onClick = {}) {
+                    Box(
+                        Modifier
+                            .size(diameter)
+                            .testTag(FilledIconButtonIconTag)
+                    )
+                }
+            }
+        }
+
+        // Icon should be centered inside the FilledIconButton
+        rule.onNodeWithTag(FilledIconButtonIconTag, useUnmergedTree = true)
+            .assertLeftPositionInRootIsEqualTo(20.dp / 2)
+            .assertTopPositionInRootIsEqualTo(20.dp / 2)
+    }
+
+    @Test
+    fun filledIconButton_defaultSize_customIconSize_iconPositioning() {
+        val diameter = 20.dp
+        rule.setContent {
+            Box {
+                IconButton(onClick = {}) {
+                    Box(
+                        Modifier
+                            .size(diameter)
+                            .testTag(FilledIconButtonIconTag)
+                    )
+                }
+            }
+        }
+
+        // Icon should be centered inside the FilledIconButton
+        rule.onNodeWithTag(FilledIconButtonIconTag, useUnmergedTree = true)
+            .assertLeftPositionInRootIsEqualTo(10.dp)
+            .assertTopPositionInRootIsEqualTo(10.dp)
+    }
+
+    @Test
+    fun outlinedIconButton_DefaultSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assertWidthIsEqualTo(40.dp)
+            .assertHeightIsEqualTo(40.dp)
+    }
+
+    @Test
+    fun outlinedIconButton_SmallSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(OutlinedIconButtonDefaults.SmallButtonSize)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assertWidthIsEqualTo(28.dp)
+            .assertHeightIsEqualTo(28.dp)
+    }
+
+    @Test
+    fun outlinedIconButton_MediumSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(OutlinedIconButtonDefaults.MediumButtonSize)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assertWidthIsEqualTo(40.dp)
+            .assertHeightIsEqualTo(40.dp)
+    }
+
+    @Test
+    fun outlinedIconButton_LargeSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(OutlinedIconButtonDefaults.LargeButtonSize)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assertWidthIsEqualTo(56.dp)
+            .assertHeightIsEqualTo(56.dp)
+    }
+
+    @Test
+    fun outlinedIconButton_CustomSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(64.dp)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assertWidthIsEqualTo(64.dp)
+            .assertHeightIsEqualTo(64.dp)
+    }
+
+    @Test
+    fun outlinedIconButton__size_withoutMinimumTouchTarget() {
+        val width = 24.dp
+        val height = 24.dp
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .testTag(OutlinedIconButtonTag)
+                    .size(width, height),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonIconSize)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag, useUnmergedTree = true)
+            .assertWidthIsEqualTo(width)
+            .assertHeightIsEqualTo(height)
+    }
+
+    @Test
+    fun outlinedIconButton_defaultSemantics() {
+        rule.setContent {
+            Box {
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(OutlinedIconButtonTag),
+                    onClick = {}
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun outlinedIconButton_disabledSemantics() {
+        rule.setContent {
+            Box {
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(OutlinedIconButtonTag),
+                    onClick = {},
+                    enabled = false
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun outlinedIconButton_findByTagAndClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            Box {
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(OutlinedIconButtonTag),
+                    onClick = onClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun outlinedIconButton_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(OutlinedIconButtonTag),
+                    onClick = { enabled = false },
+                    enabled = enabled
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+        rule.onNodeWithTag(OutlinedIconButtonTag)
+            // Confirm the button starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun outlinedIconButton_clickIsIndependentBetweenButtons() {
+        var addButtonCounter = 0
+        val addButtonOnClick: () -> Unit = { ++addButtonCounter }
+        val addButtonTag = "AddButton"
+
+        var phoneButtonCounter = 0
+        val phoneButtonOnClick: () -> Unit = { ++phoneButtonCounter }
+        val phoneButtonTag = "PhoneButton"
+
+        rule.setContent {
+            Column {
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(addButtonTag),
+                    onClick = addButtonOnClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+                OutlinedIconButton(
+                    modifier = Modifier.testTag(phoneButtonTag),
+                    onClick = phoneButtonOnClick
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .size(OutlinedIconButtonDefaults.MediumIconSize)
+                            .semantics(mergeDescendants = true) {}
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(addButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(addButtonCounter).isEqualTo(1)
+            Truth.assertThat(phoneButtonCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(phoneButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(addButtonCounter).isEqualTo(1)
+            Truth.assertThat(phoneButtonCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun outlinedIconButton_PositioningSmallSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(OutlinedIconButtonDefaults.SmallButtonSize)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonDefaults.SmallIconSize)
+                        .testTag(OutlinedIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(OutlinedIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(OutlinedIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            6.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            6.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            6.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            6.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun outlinedIconButton_PositioningDefaultOrMediumSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier.testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonDefaults.MediumIconSize)
+                        .testTag(OutlinedIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(OutlinedIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(OutlinedIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            10.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            10.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            10.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            10.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun outlinedIconButton_PositioningLargeSize() {
+        rule.setContent {
+            OutlinedIconButton(
+                modifier = Modifier
+                    .size(OutlinedIconButtonDefaults.LargeButtonSize)
+                    .testTag(OutlinedIconButtonTag),
+                onClick = {}
+            ) {
+                Box(
+                    modifier = Modifier
+                        .size(OutlinedIconButtonDefaults.LargeIconSize)
+                        .testTag(OutlinedIconButtonIconTag)
+                        .semantics(mergeDescendants = true) {}
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(OutlinedIconButtonTag).getUnclippedBoundsInRoot()
+        val iconBounds = rule.onNodeWithTag(OutlinedIconButtonIconTag).getUnclippedBoundsInRoot()
+
+        (iconBounds.left - buttonBounds.left).assertIsEqualTo(
+            14.dp,
+            "padding between the start of the button and the start of the icon."
+        )
+
+        (iconBounds.top - buttonBounds.top).assertIsEqualTo(
+            14.dp,
+            "padding between the top of the button and the top of the icon."
+        )
+
+        (buttonBounds.right - iconBounds.right).assertIsEqualTo(
+            14.dp,
+            "padding between the end of the icon and the end of the button."
+        )
+
+        (buttonBounds.bottom - iconBounds.bottom).assertIsEqualTo(
+            14.dp,
+            "padding between the bottom of the button and the bottom of the icon."
+        )
+    }
+
+    @Test
+    fun outlinedIconButton_defaultSize_materialIconSize_iconPositioning() {
+        val diameter = OutlinedIconButtonDefaults.MediumIconSize
+        rule.setContent {
+            Box {
+                OutlinedIconButton(onClick = {}) {
+                    Box(
+                        Modifier
+                            .size(diameter)
+                            .testTag(OutlinedIconButtonIconTag)
+                    )
+                }
+            }
+        }
+
+        // Icon should be centered inside the OutlinedIconButton
+        rule.onNodeWithTag(OutlinedIconButtonIconTag, useUnmergedTree = true)
+            .assertLeftPositionInRootIsEqualTo(20.dp / 2)
+            .assertTopPositionInRootIsEqualTo(20.dp / 2)
+    }
+
+    @Test
+    fun outlinedIconButton_defaultSize_customIconSize_iconPositioning() {
+        val diameter = 20.dp
+        rule.setContent {
+            Box {
+                OutlinedIconButton(onClick = {}) {
+                    Box(
+                        Modifier
+                            .size(diameter)
+                            .testTag(OutlinedIconButtonIconTag)
+                    )
+                }
+            }
+        }
+
+        // Icon should be centered inside the OutlinedIconButton
+        rule.onNodeWithTag(OutlinedIconButtonIconTag, useUnmergedTree = true)
+            .assertLeftPositionInRootIsEqualTo(10.dp)
+            .assertTopPositionInRootIsEqualTo(10.dp)
+    }
+}
+
+private const val FilledIconButtonTag = "FilledIconButton"
+private const val FilledIconButtonIconTag = "FilledIconButtonIcon"
+private val FilledIconButtonIconSize = 18.0.dp
+
+private const val OutlinedIconButtonTag = "OutlinedIconButton"
+private const val OutlinedIconButtonIconTag = "OutlinedIconButtonIcon"
+private val OutlinedIconButtonIconSize = 18.0.dp
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ModalNavigationDrawerTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ModalNavigationDrawerTest.kt
index ba9bc9b..a522dc83 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ModalNavigationDrawerTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ModalNavigationDrawerTest.kt
@@ -109,8 +109,8 @@
                 drawerState = navigationDrawerValue,
                 drawerContent = {
                     BasicText(
-                        text =
-                        if (it == DrawerValue.Open) "Opened" else "Closed"
+                        modifier = Modifier.focusable(),
+                        text = if (it == DrawerValue.Open) "Opened" else "Closed"
                     )
                 }) { BasicText("other content") }
         }
@@ -138,7 +138,10 @@
                         .focusable(false),
                     drawerState = navigationDrawerValue,
                     drawerContent = {
-                        BasicText(text = if (it == DrawerValue.Open) "Opened" else "Closed")
+                        BasicText(
+                            modifier = Modifier.focusable(),
+                            text = if (it == DrawerValue.Open) "Opened" else "Closed"
+                        )
                     }) {
                     Box(modifier = Modifier.focusable()) {
                         BasicText("Button")
@@ -154,7 +157,7 @@
         rule.onAllNodesWithText("Closed").assertAnyAreDisplayed()
     }
 
-    @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
+    @OptIn(ExperimentalTestApi::class)
     @Test
     fun modalNavigationDrawer_focusMovesIntoDrawer_openStateComposableDisplayed() {
         InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerTest.kt
index d1aedfa..c7d8840 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/NavigationDrawerTest.kt
@@ -105,8 +105,8 @@
                 drawerState = navigationDrawerValue,
                 drawerContent = {
                     BasicText(
-                        text =
-                        if (it == DrawerValue.Open) "Opened" else "Closed"
+                        modifier = Modifier.focusable(),
+                        text = if (it == DrawerValue.Open) "Opened" else "Closed"
                     )
                 }) { BasicText("other content") }
         }
@@ -132,7 +132,10 @@
                     modifier = Modifier.focusRequester(drawerFocusRequester),
                     drawerState = navigationDrawerValue,
                     drawerContent = {
-                        BasicText(text = if (it == DrawerValue.Open) "Opened" else "Closed")
+                        BasicText(
+                            text = if (it == DrawerValue.Open) "Opened" else "Closed",
+                            modifier = Modifier.focusable()
+                        )
                     }) {
                     Box(modifier = Modifier.focusable()) {
                         BasicText("Button")
@@ -335,7 +338,10 @@
                 modifier = Modifier.focusRequester(drawerFocusRequester),
                 drawerState = navigationDrawerValue,
                 drawerContent = {
-                    BasicText(text = if (it == DrawerValue.Open) "Opened" else "Closed")
+                    BasicText(
+                        modifier = Modifier.focusable(),
+                        text = if (it == DrawerValue.Open) "Opened" else "Closed"
+                    )
                 }) { BasicText("other content") }
         }
 
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonScreenshotTest.kt
new file mode 100644
index 0000000..1ee53ca
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonScreenshotTest.kt
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import android.os.Build
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.hasClickAction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class WideButtonScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    @Test
+    fun defaultWideButton_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(onClick = { }) {
+                    Text("Settings")
+                }
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_light_theme")
+    }
+
+    @Test
+    fun defaultWideButton_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(onClick = { }) {
+                    Text("Settings")
+                }
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_dark_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(onClick = { }, enabled = false) {
+                    Text("Settings")
+                }
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_disabled_light_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(onClick = { }, enabled = false) {
+                    Text("Settings")
+                }
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_disabled_dark_theme")
+    }
+
+    @Test
+    fun wideButton_withSubtitle_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_subtitle_light_theme")
+    }
+
+    @Test
+    fun wideButton_withSubtitle_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_subtitle_dark_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_withSubtitle_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "disabled_wide_button_with_subtitle_light_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_withSubtitle_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "disabled_wide_button_with_subtitle_dark_theme")
+    }
+
+    @Test
+    fun wideButton_withIcon_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_icon_light_theme")
+    }
+
+    @Test
+    fun wideButton_withIcon_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_icon_dark_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_withIcon_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "disabled_wide_button_with_icon_light_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_withIcon_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "disabled_wide_button_with_icon_dark_theme")
+    }
+
+    @Test
+    fun wideButton_withSubtitleAndIcon_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_subtitle_and_icon_light_theme")
+    }
+
+    @Test
+    fun wideButton_withSubtitleAndIcon_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, "wide_button_with_subtitle_and_icon_dark_theme")
+    }
+
+    @Test
+    fun disabled_wideButton_withSubtitleAndIcon_lightTheme() {
+        rule.setContent {
+            LightMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(
+                screenshotRule,
+                "disabled_wide_button_with_subtitle_and_icon_light_theme"
+            )
+    }
+
+    @Test
+    fun disabled_wideButton_withSubtitleAndIcon_darkTheme() {
+        rule.setContent {
+            DarkMaterialTheme {
+                WideButton(
+                    onClick = { },
+                    enabled = false,
+                    title = { Text("Settings") },
+                    subtitle = { Text(text = "Update device preferences") },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "Settings"
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.onNode(hasClickAction())
+            .captureToImage()
+            .assertAgainstGolden(
+                screenshotRule,
+                "disabled_wide_button_with_subtitle_and_icon_dark_theme"
+            )
+    }
+}
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt
new file mode 100644
index 0000000..d7d9625
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/WideButtonTest.kt
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsEqualTo
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(
+    ExperimentalComposeUiApi::class,
+    ExperimentalTestApi::class,
+    ExperimentalTvMaterial3Api::class
+)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class WideButtonTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun wideButton_defaultSemantics() {
+        rule.setContent {
+            Box {
+                WideButton(
+                    onClick = { },
+                    modifier = Modifier
+                        .testTag(WideButtonTag),
+                    title = { Text(text = "Settings") },
+                    icon = {
+                        Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+                    },
+                    subtitle = { Text(text = "Update device preferences") }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(WideButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun wideButton_disabledSemantics() {
+        rule.setContent {
+            Box {
+                WideButton(
+                    onClick = { },
+                    modifier = Modifier
+                        .testTag(WideButtonTag),
+                    enabled = false,
+                    title = { Text(text = "Settings") },
+                    icon = {
+                        Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+                    },
+                    subtitle = { Text(text = "Update device preferences") }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(WideButtonTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun wideButton_findByTagAndClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            Box {
+                WideButton(
+                    onClick = onClick,
+                    modifier = Modifier
+                        .testTag(WideButtonTag),
+                    title = { Text(text = "Settings") },
+                    icon = {
+                        Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+                    },
+                    subtitle = { Text(text = "Update device preferences") }
+                )
+            }
+        }
+        rule.onNodeWithTag(WideButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun wideButton_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                WideButton(
+                    onClick = { enabled = false },
+                    modifier = Modifier
+                        .testTag(WideButtonTag),
+                    enabled = enabled,
+                    title = { Text(text = "Settings") },
+                    icon = {
+                        Icon(imageVector = Icons.Default.Settings, contentDescription = "")
+                    },
+                    subtitle = { Text(text = "Update device preferences") }
+                )
+            }
+        }
+        rule.onNodeWithTag(WideButtonTag)
+            // Confirm the button starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun wideButton_clickIsIndependentBetweenButtons() {
+        var watchButtonCounter = 0
+        val watchButtonOnClick: () -> Unit = { ++watchButtonCounter }
+        val watchButtonTag = "WatchButton"
+
+        var playButtonCounter = 0
+        val playButtonOnClick: () -> Unit = { ++playButtonCounter }
+        val playButtonTag = "PlayButton"
+
+        rule.setContent {
+            Column {
+                WideButton(
+                    onClick = watchButtonOnClick,
+                    modifier = Modifier.testTag(watchButtonTag),
+                ) {
+                    Text(text = "Watch")
+                }
+                WideButton(
+                    onClick = playButtonOnClick,
+                    modifier = Modifier.testTag(playButtonTag),
+                ) {
+                    Text(text = "Play")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(watchButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(watchButtonCounter).isEqualTo(1)
+            Truth.assertThat(playButtonCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(playButtonTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(watchButtonCounter).isEqualTo(1)
+            Truth.assertThat(playButtonCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun wideButton_buttonPositioning() {
+        rule.setContent {
+            Box {
+                WideButton(
+                    onClick = { },
+                    modifier = Modifier
+                        .testTag(WideButtonTag),
+                    contentPadding = WideButtonDefaults.ContentPadding,
+                    title = {
+                        Text(
+                            text = "Email",
+                            modifier = Modifier
+                                .testTag(WideButtonTextTag)
+                                .semantics(mergeDescendants = true) {}
+                        )
+                            },
+                    icon = {
+                        Icon(
+                            imageVector = Icons.Default.Settings,
+                            contentDescription = "",
+                            modifier = Modifier
+                                .size(WideButtonIconSize)
+                                .testTag(WideButtonIconTag)
+                                .semantics(mergeDescendants = true) {}
+                        )
+                    }
+                )
+            }
+        }
+
+        val buttonBounds = rule.onNodeWithTag(WideButtonTag).getUnclippedBoundsInRoot()
+        val leadingIconBounds = rule.onNodeWithTag(WideButtonIconTag).getUnclippedBoundsInRoot()
+
+        (leadingIconBounds.left - buttonBounds.left).assertIsEqualTo(
+            16.dp,
+            "padding between the start of the button and the start of the leading icon."
+        )
+    }
+}
+
+private val WideButtonIconSize = 18.0.dp
+private const val WideButtonTag = "WideButtonTag"
+private const val WideButtonTextTag = "WideButtonText"
+private const val WideButtonIconTag = "WideButtonIcon"
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
index cf59b79..b547d9d 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Button.kt
@@ -211,55 +211,3 @@
         }
     }
 }
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonShape.toClickableSurfaceShape(): ClickableSurfaceShape = ClickableSurfaceShape(
-    shape = shape,
-    focusedShape = focusedShape,
-    pressedShape = pressedShape,
-    disabledShape = disabledShape,
-    focusedDisabledShape = focusedDisabledShape
-)
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonColors.toClickableSurfaceContainerColor(): ClickableSurfaceColor =
-    ClickableSurfaceColor(
-        color = containerColor,
-        focusedColor = focusedContainerColor,
-        pressedColor = pressedContainerColor,
-        disabledColor = disabledContainerColor,
-    )
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonColors.toClickableSurfaceContentColor(): ClickableSurfaceColor =
-    ClickableSurfaceColor(
-        color = contentColor,
-        focusedColor = focusedContentColor,
-        pressedColor = pressedContentColor,
-        disabledColor = disabledContentColor,
-    )
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonScale.toClickableSurfaceScale() = ClickableSurfaceScale(
-    scale = scale,
-    focusedScale = focusedScale,
-    pressedScale = pressedScale,
-    disabledScale = disabledScale,
-    focusedDisabledScale = focusedDisabledScale
-)
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonBorder.toClickableSurfaceBorder() = ClickableSurfaceBorder(
-    border = border,
-    focusedBorder = focusedBorder,
-    pressedBorder = pressedBorder,
-    disabledBorder = disabledBorder,
-    focusedDisabledBorder = focusedDisabledBorder
-)
-
-@OptIn(ExperimentalTvMaterial3Api::class)
-private fun ButtonGlow.toClickableSurfaceGlow() = ClickableSurfaceGlow(
-    glow = glow,
-    focusedGlow = focusedGlow,
-    pressedGlow = pressedGlow
-)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
index 89fe0a7..560ad85 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
@@ -122,6 +122,47 @@
 }
 
 /**
+ * Defines [Color]s for all TV [Interaction] states of a WideButton
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class WideButtonContentColor internal constructor(
+    internal val contentColor: Color,
+    internal val focusedContentColor: Color,
+    internal val pressedContentColor: Color,
+    internal val disabledContentColor: Color,
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as WideButtonContentColor
+
+        if (contentColor != other.contentColor) return false
+        if (focusedContentColor != other.focusedContentColor) return false
+        if (pressedContentColor != other.pressedContentColor) return false
+        if (disabledContentColor != other.disabledContentColor) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = contentColor.hashCode()
+        result = 31 * result + focusedContentColor.hashCode()
+        result = 31 * result + pressedContentColor.hashCode()
+        result = 31 * result + disabledContentColor.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "WideButtonContentColor(contentColor=$contentColor, " +
+            "focusedContentColor=$focusedContentColor, " +
+            "pressedContentColor=$pressedContentColor, " +
+            "disabledContentColor=$disabledContentColor)"
+    }
+}
+
+/**
  * Defines the scale for all TV [Interaction] states of Button.
  */
 @ExperimentalTvMaterial3Api
@@ -243,3 +284,64 @@
         return "ButtonGlow(glow=$glow, focusedGlow=$focusedGlow, pressedGlow=$pressedGlow)"
     }
 }
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonShape.toClickableSurfaceShape(): ClickableSurfaceShape = ClickableSurfaceShape(
+    shape = shape,
+    focusedShape = focusedShape,
+    pressedShape = pressedShape,
+    disabledShape = disabledShape,
+    focusedDisabledShape = focusedDisabledShape
+)
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonColors.toClickableSurfaceContainerColor(): ClickableSurfaceColor =
+    ClickableSurfaceColor(
+        color = containerColor,
+        focusedColor = focusedContainerColor,
+        pressedColor = pressedContainerColor,
+        disabledColor = disabledContainerColor,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonColors.toClickableSurfaceContentColor(): ClickableSurfaceColor =
+    ClickableSurfaceColor(
+        color = contentColor,
+        focusedColor = focusedContentColor,
+        pressedColor = pressedContentColor,
+        disabledColor = disabledContentColor,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun WideButtonContentColor.toClickableSurfaceContentColor(): ClickableSurfaceColor =
+    ClickableSurfaceColor(
+        color = contentColor,
+        focusedColor = focusedContentColor,
+        pressedColor = pressedContentColor,
+        disabledColor = disabledContentColor,
+    )
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonScale.toClickableSurfaceScale() = ClickableSurfaceScale(
+    scale = scale,
+    focusedScale = focusedScale,
+    pressedScale = pressedScale,
+    disabledScale = disabledScale,
+    focusedDisabledScale = focusedDisabledScale
+)
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonBorder.toClickableSurfaceBorder() = ClickableSurfaceBorder(
+    border = border,
+    focusedBorder = focusedBorder,
+    pressedBorder = pressedBorder,
+    disabledBorder = disabledBorder,
+    focusedDisabledBorder = focusedDisabledBorder
+)
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+internal fun ButtonGlow.toClickableSurfaceGlow() = ClickableSurfaceGlow(
+    glow = glow,
+    focusedGlow = focusedGlow,
+    pressedGlow = pressedGlow
+)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
index 1a5d6c7..1c1fc72 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Card.kt
@@ -20,15 +20,25 @@
 import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.unit.dp
 
 /**
@@ -82,16 +92,300 @@
 }
 
 /**
+ * [ClassicCard] is an opinionated TV Material card that offers a 4 slot layout to show
+ * information about a subject.
+ *
+ * This card has a vertical layout with the interactive surface [Surface], which provides the image
+ * slot at the top, followed by the title, subtitle, and description slots.
+ *
+ * This Card handles click events, calling its [onClick] lambda.
+ *
+ * @param onClick called when this card is clicked
+ * @param image defines the [Composable] image to be displayed on top of the Card.
+ * @param title defines the [Composable] title placed below the image in the Card.
+ * @param modifier the [Modifier] to be applied to this card.
+ * @param subtitle defines the [Composable] supporting text placed below the title of the Card.
+ * @param description defines the [Composable] description placed below the subtitle of the Card.
+ * @param shape [CardShape] defines the shape of this card's container in different interaction
+ * states. See [CardDefaults.shape].
+ * @param colors [CardColors] defines the background & content colors used in this card for
+ * different interaction states. See [CardDefaults.colors].
+ * @param scale [CardScale] defines size of the card relative to its original size for different
+ * interaction states. See [CardDefaults.scale].
+ * @param border [CardBorder] defines a border around the card for different interaction states.
+ * See [CardDefaults.border].
+ * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
+ * states. See [CardDefaults.glow].
+ * @param contentPadding [PaddingValues] defines the inner padding applied to the card's content.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this card. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this card in different states.
+ */
+@ExperimentalTvMaterial3Api
+@Composable
+fun ClassicCard(
+    onClick: () -> Unit,
+    image: @Composable BoxScope.() -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    shape: CardShape = CardDefaults.shape(),
+    colors: CardColors = CardDefaults.colors(),
+    scale: CardScale = CardDefaults.scale(),
+    border: CardBorder = CardDefaults.border(),
+    glow: CardGlow = CardDefaults.glow(),
+    contentPadding: PaddingValues = PaddingValues(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+    Card(
+        onClick = onClick,
+        modifier = modifier,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow
+    ) {
+        Column(
+            modifier = Modifier.padding(contentPadding)
+        ) {
+            Box(
+                contentAlignment = CardDefaults.ContentImageAlignment,
+                content = image
+            )
+            Column {
+                CardContent(
+                    title = title,
+                    subtitle = subtitle,
+                    description = description
+                )
+            }
+        }
+    }
+}
+
+/**
+ * [CompactCard] is an opinionated TV Material card that offers a 4 slot layout to show
+ * information about a subject.
+ *
+ * This card provides the interactive surface [Surface] with the image slot as the background
+ * (with an overlay scrim gradient). Other slots for the title, subtitle, and description are
+ * placed over it.
+ *
+ * This Card handles click events, calling its [onClick] lambda.
+ *
+ * @param onClick called when this card is clicked
+ * @param image defines the [Composable] image to be displayed on top of the Card.
+ * @param title defines the [Composable] title placed below the image in the Card.
+ * @param modifier the [Modifier] to be applied to this card.
+ * @param subtitle defines the [Composable] supporting text placed below the title of the Card.
+ * @param description defines the [Composable] description placed below the subtitle of the Card.
+ * @param shape [CardShape] defines the shape of this card's container in different interaction
+ * states. See [CardDefaults.shape].
+ * @param colors [CardColors] defines the background & content colors used in this card for
+ * different interaction states. See [CardDefaults.compactCardColors].
+ * @param scale [CardScale] defines size of the card relative to its original size for different
+ * interaction states. See [CardDefaults.scale].
+ * @param border [CardBorder] defines a border around the card for different interaction states.
+ * See [CardDefaults.border].
+ * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
+ * states. See [CardDefaults.glow].
+ * @param scrimBrush [Brush] defines a brush/gradient to be used to draw the scrim over the image
+ * in the background. See [CardDefaults.ContainerGradient].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this card. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this card in different states.
+ */
+@ExperimentalTvMaterial3Api
+@Composable
+fun CompactCard(
+    onClick: () -> Unit,
+    image: @Composable BoxScope.() -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    shape: CardShape = CardDefaults.shape(),
+    colors: CardColors = CardDefaults.compactCardColors(),
+    scale: CardScale = CardDefaults.scale(),
+    border: CardBorder = CardDefaults.border(),
+    glow: CardGlow = CardDefaults.glow(),
+    scrimBrush: Brush = CardDefaults.ContainerGradient,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+    Card(
+        onClick = onClick,
+        modifier = modifier,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow
+    ) {
+        Box(contentAlignment = Alignment.BottomStart) {
+            Box(
+                modifier = Modifier
+                    .drawWithCache {
+                        onDrawWithContent {
+                            drawContent()
+                            drawRect(brush = scrimBrush)
+                        }
+                    },
+                contentAlignment = CardDefaults.ContentImageAlignment,
+                content = image
+            )
+            Column {
+                CardContent(
+                    title = title,
+                    subtitle = subtitle,
+                    description = description
+                )
+            }
+        }
+    }
+}
+
+/**
+ * [WideClassicCard] is an opinionated TV Material card that offers a 4 slot layout to show
+ * information about a subject.
+ *
+ * This card has a horizontal layout with the interactive surface [Surface], which provides the
+ * image slot at the start, followed by the title, subtitle, and description slots at the end.
+ *
+ * This Card handles click events, calling its [onClick] lambda.
+ *
+ * @param onClick called when this card is clicked
+ * @param image defines the [Composable] image to be displayed on top of the Card.
+ * @param title defines the [Composable] title placed below the image in the Card.
+ * @param modifier the [Modifier] to be applied to this card.
+ * @param subtitle defines the [Composable] supporting text placed below the title of the Card.
+ * @param description defines the [Composable] description placed below the subtitle of the Card.
+ * @param shape [CardShape] defines the shape of this card's container in different interaction
+ * states. See [CardDefaults.shape].
+ * @param colors [CardColors] defines the background & content colors used in this card for
+ * different interaction states. See [CardDefaults.colors].
+ * @param scale [CardScale] defines size of the card relative to its original size for different
+ * interaction states. See [CardDefaults.scale].
+ * @param border [CardBorder] defines a border around the card for different interaction states.
+ * See [CardDefaults.border].
+ * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
+ * states. See [CardDefaults.glow].
+ * @param contentPadding [PaddingValues] defines the inner padding applied to the card's content.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this card. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this card in different states.
+ */
+@ExperimentalTvMaterial3Api
+@Composable
+fun WideClassicCard(
+    onClick: () -> Unit,
+    image: @Composable BoxScope.() -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    shape: CardShape = CardDefaults.shape(),
+    colors: CardColors = CardDefaults.colors(),
+    scale: CardScale = CardDefaults.scale(),
+    border: CardBorder = CardDefaults.border(),
+    glow: CardGlow = CardDefaults.glow(),
+    contentPadding: PaddingValues = PaddingValues(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+    Card(
+        onClick = onClick,
+        modifier = modifier,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow
+    ) {
+        Row(
+            modifier = Modifier.padding(contentPadding)
+        ) {
+            Box(
+                contentAlignment = CardDefaults.ContentImageAlignment,
+                content = image
+            )
+            Column {
+                CardContent(
+                    title = title,
+                    subtitle = subtitle,
+                    description = description
+                )
+            }
+        }
+    }
+}
+
+@Composable
+internal fun CardContent(
+    title: @Composable () -> Unit,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {}
+) {
+    ProvideTextStyle(MaterialTheme.typography.titleMedium) {
+        title.invoke()
+    }
+    ProvideTextStyle(MaterialTheme.typography.bodySmall) {
+        Box(Modifier.graphicsLayer { alpha = SubtitleAlpha }) {
+            subtitle.invoke()
+        }
+    }
+    ProvideTextStyle(MaterialTheme.typography.bodySmall) {
+        Box(Modifier.graphicsLayer { alpha = DescriptionAlpha }) {
+            description.invoke()
+        }
+    }
+}
+
+/**
  * Contains the default values used by all card types.
  */
 @ExperimentalTvMaterial3Api
 object CardDefaults {
+    internal val ContentImageAlignment = Alignment.Center
+
     /**
-    * The default [Shape] used by Cards.
-    */
+     * The default [Shape] used by Cards.
+     */
     private val ContainerShape = RoundedCornerShape(8.dp)
 
     /**
+     * Recommended aspect ratio [Float] to get square images, can be applied using the modifier
+     * [Modifier.aspectRatio].
+     */
+    const val SquareImageAspectRatio = 1f
+
+    /**
+     * Recommended aspect ratio [Float] for vertical images, can be applied using the modifier
+     * [Modifier.aspectRatio].
+     */
+    const val VerticalImageAspectRatio = 2f / 3
+
+    /**
+     * Recommended aspect ratio [Float] for horizontal images, can be applied using the modifier
+     * [Modifier.aspectRatio].
+     */
+    const val HorizontalImageAspectRatio = 16f / 9
+
+    /**
+     * Gradient used in cards to give more emphasis to the textual content that is generally
+     * displayed above an image.
+     */
+    val ContainerGradient = Brush.verticalGradient(
+        listOf(
+            Color(red = 28, green = 27, blue = 31, alpha = 0),
+            Color(red = 28, green = 27, blue = 31, alpha = 204)
+        )
+    )
+
+    /**
      * Creates a [CardShape] that represents the default container shapes used in a Card.
      *
      * @param shape the default shape used when the Card has no other [Interaction]s.
@@ -121,7 +415,7 @@
     @ReadOnlyComposable
     @Composable
     fun colors(
-        containerColor: Color = MaterialTheme.colorScheme.surface,
+        containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
         contentColor: Color = contentColorFor(containerColor),
         focusedContainerColor: Color = containerColor,
         focusedContentColor: Color = contentColorFor(focusedContainerColor),
@@ -137,6 +431,34 @@
     )
 
     /**
+     * Creates [CardColors] that represents the default colors used in a Compact Card.
+     *
+     * @param containerColor the default container color of this Card.
+     * @param contentColor the default content color of this Card.
+     * @param focusedContainerColor the container color of this Card when focused.
+     * @param focusedContentColor the content color of this Card when focused.
+     * @param pressedContainerColor the container color of this Card when pressed.
+     * @param pressedContentColor the content color of this Card when pressed.
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun compactCardColors(
+        containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
+        contentColor: Color = Color.White,
+        focusedContainerColor: Color = containerColor,
+        focusedContentColor: Color = contentColor,
+        pressedContainerColor: Color = focusedContainerColor,
+        pressedContentColor: Color = focusedContentColor
+    ) = CardColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor
+    )
+
+    /**
      * Creates a [CardScale] that represents the default scales used in a Card.
      * Scales are used to modify the size of a composable in different [Interaction] states
      * e.g. 1f (original) in default state, 1.1f (scaled up) in focused state, 0.8f (scaled down)
@@ -200,6 +522,9 @@
     )
 }
 
+private const val SubtitleAlpha = 0.6f
+private const val DescriptionAlpha = 0.8f
+
 @OptIn(ExperimentalTvMaterial3Api::class)
 private fun CardColors.toClickableSurfaceContainerColor() =
     ClickableSurfaceColor(
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt b/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt
new file mode 100644
index 0000000..92aa581
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/CardLayout.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+
+/**
+ * [StandardCardLayout] is an opinionated TV Material Card layout with an image and text content
+ * to show information about a subject.
+ *
+ * It provides a vertical layout with an image card slot at the top. And below that, there are
+ * slots for the title, subtitle and description.
+ *
+ * @param imageCard defines the [Composable] to be used for the image card. See
+ * [CardLayoutDefaults.ImageCard] to create an image card. The `interactionSource` param provided
+ * in the lambda function should be forwarded and used with the image card composable.
+ * @param title defines the [Composable] title placed below the image card in the CardLayout.
+ * @param modifier the [Modifier] to be applied to this CardLayout.
+ * @param subtitle defines the [Composable] supporting text placed below the title in CardLayout.
+ * @param description defines the [Composable] description placed below the subtitle in CardLayout.
+ * @param contentColor [CardLayoutColors] defines the content color used in the CardLayout
+ * for different interaction states. See [CardLayoutDefaults.contentColor].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this CardLayout. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this card layout in different states.
+ * This interaction source param would also be forwarded to be used with the `imageCard` composable.
+ */
+@ExperimentalTvMaterial3Api
+@Composable
+fun StandardCardLayout(
+    imageCard: @Composable (interactionSource: MutableInteractionSource) -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    contentColor: CardLayoutColors = CardLayoutDefaults.contentColor(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+    val focused by interactionSource.collectIsFocusedAsState()
+    val pressed by interactionSource.collectIsPressedAsState()
+
+    Column(
+        modifier = modifier
+    ) {
+        Box(
+            contentAlignment = CardDefaults.ContentImageAlignment,
+        ) {
+            imageCard(interactionSource)
+        }
+        Column(
+            modifier = Modifier
+                .align(Alignment.CenterHorizontally),
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+            CardLayoutContent(
+                title = title,
+                subtitle = subtitle,
+                description = description,
+                contentColor = contentColor.color(
+                    focused = focused,
+                    pressed = pressed
+                )
+            )
+        }
+    }
+}
+
+/**
+ * [WideCardLayout] is an opinionated TV Material Card layout with an image and text content
+ * to show information about a subject.
+ *
+ * It provides a horizontal layout with an image card slot at the start, followed by the title,
+ * subtitle and description at the end.
+ *
+ * @param imageCard defines the [Composable] to be used for the image card. See
+ * [CardLayoutDefaults.ImageCard] to create an image card. The `interactionSource` param provided
+ * in the lambda function should to be forwarded and used with the image card composable.
+ * @param title defines the [Composable] title placed below the image card in the CardLayout.
+ * @param modifier the [Modifier] to be applied to this CardLayout.
+ * @param subtitle defines the [Composable] supporting text placed below the title in CardLayout.
+ * @param description defines the [Composable] description placed below the subtitle in CardLayout.
+ * @param contentColor [CardLayoutColors] defines the content color used in the CardLayout
+ * for different interaction states. See [CardLayoutDefaults.contentColor].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this CardLayout. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this card layout in different states.
+ * This interaction source param would also be forwarded to be used with the `imageCard` composable.
+ */
+@ExperimentalTvMaterial3Api
+@Composable
+fun WideCardLayout(
+    imageCard: @Composable (interactionSource: MutableInteractionSource) -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    contentColor: CardLayoutColors = CardLayoutDefaults.contentColor(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+) {
+    val focused by interactionSource.collectIsFocusedAsState()
+    val pressed by interactionSource.collectIsPressedAsState()
+
+    Row(
+        modifier = modifier
+    ) {
+        Box(
+            contentAlignment = CardDefaults.ContentImageAlignment
+        ) {
+            imageCard(interactionSource)
+        }
+        Column {
+            CardLayoutContent(
+                title = title,
+                subtitle = subtitle,
+                description = description,
+                contentColor = contentColor.color(
+                    focused = focused,
+                    pressed = pressed
+                )
+            )
+        }
+    }
+}
+
+@Composable
+internal fun CardLayoutContent(
+    title: @Composable () -> Unit,
+    subtitle: @Composable () -> Unit = {},
+    description: @Composable () -> Unit = {},
+    contentColor: Color
+) {
+    CompositionLocalProvider(LocalContentColor provides contentColor) {
+        CardContent(title, subtitle, description)
+    }
+}
+
+@ExperimentalTvMaterial3Api
+object CardLayoutDefaults {
+    /**
+     * Creates [CardLayoutColors] that represents the default content colors used in a
+     * CardLayout.
+     *
+     * @param contentColor the default content color of this CardLayout.
+     * @param focusedContentColor the content color of this CardLayout when focused.
+     * @param pressedContentColor the content color of this CardLayout when pressed.
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun contentColor(
+        contentColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = contentColor,
+        pressedContentColor: Color = focusedContentColor
+    ) = CardLayoutColors(
+        contentColor = contentColor,
+        focusedContentColor = focusedContentColor,
+        pressedContentColor = pressedContentColor
+    )
+
+    /**
+     * [ImageCard] is basically a [Card] composable with an image as the content. It is recommended
+     * to be used with the different CardLayout(s).
+     *
+     * This Card handles click events, calling its [onClick] lambda.
+     *
+     * @param onClick called when this card is clicked
+     * @param interactionSource the [MutableInteractionSource] representing the stream of
+     * [Interaction]s for this card. When using with the CardLayout(s), it is recommended to
+     * pass in the interaction state obtained from the parent lambda.
+     * @param modifier the [Modifier] to be applied to this card
+     * @param shape [CardShape] defines the shape of this card's container in different interaction
+     * states. See [CardDefaults.shape].
+     * @param colors [CardColors] defines the background & content colors used in this card for
+     * different interaction states. See [CardDefaults.colors].
+     * @param scale [CardScale] defines size of the card relative to its original size for different
+     * interaction states. See [CardDefaults.scale].
+     * @param border [CardBorder] defines a border around the card for different interaction states.
+     * See [CardDefaults.border].
+     * @param glow [CardGlow] defines a shadow to be shown behind the card for different interaction
+     * states. See [CardDefaults.glow].
+     * @param content defines the image content [Composable] to be displayed inside the Card.
+     */
+    @Composable
+    fun ImageCard(
+        onClick: () -> Unit,
+        interactionSource: MutableInteractionSource,
+        modifier: Modifier = Modifier,
+        shape: CardShape = CardDefaults.shape(),
+        colors: CardColors = CardDefaults.colors(),
+        scale: CardScale = CardDefaults.scale(),
+        border: CardBorder = CardDefaults.border(),
+        glow: CardGlow = CardDefaults.glow(),
+        content: @Composable () -> Unit
+    ) {
+        Card(
+            onClick = onClick,
+            modifier = modifier,
+            shape = shape,
+            colors = colors,
+            scale = scale,
+            border = border,
+            glow = glow,
+            interactionSource = interactionSource
+        ) {
+            content()
+        }
+    }
+}
+
+/**
+ * Represents the [Color] of content in a CardLayout for different interaction states.
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class CardLayoutColors internal constructor(
+    internal val contentColor: Color,
+    internal val focusedContentColor: Color,
+    internal val pressedContentColor: Color,
+) {
+    /**
+     * Returns the content color [Color] for different interaction states.
+     */
+    internal fun color(
+        focused: Boolean,
+        pressed: Boolean
+    ): Color {
+        return when {
+            focused -> focusedContentColor
+            pressed -> pressedContentColor
+            else -> contentColor
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as CardLayoutColors
+
+        if (contentColor != other.contentColor) return false
+        if (focusedContentColor != other.focusedContentColor) return false
+        if (pressedContentColor != other.pressedContentColor) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = contentColor.hashCode()
+        result = 31 * result + focusedContentColor.hashCode()
+        result = 31 * result + pressedContentColor.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "CardLayoutContentColor(" +
+            "contentColor=$contentColor, " +
+            "focusedContentColor=$focusedContentColor, " +
+            "pressedContentColor=$pressedContentColor)"
+    }
+}
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt b/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt
new file mode 100644
index 0000000..1c66a17
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/IconButton.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.NonRestartableComposable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+
+/**
+ * Material Design standard icon button for TV.
+ *
+ * Icon buttons help people take supplementary actions with a single tap. They’re used when a
+ * compact button is required, such as in a toolbar or image list.
+ *
+ * [content] should typically be an [Icon]. If using a custom icon, note that the typical size for
+ * the internal icon is 24 x 24 dp.
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param onClick called when this button is clicked
+ * @param modifier the [Modifier] to be applied to this button
+ * @param enabled controls the enabled state of this button. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services.
+ * @param scale Defines size of the Button relative to its original size.
+ * @param glow Shadow to be shown behind the Button.
+ * @param shape Defines the Button's shape.
+ * @param colors Color to be used for background and content of the Button
+ * @param border Defines a border around the Button.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this button. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this button in different states.
+ * @param content the content of the button, typically an [Icon]
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun IconButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    scale: ButtonScale = IconButtonDefaults.scale(),
+    glow: ButtonGlow = IconButtonDefaults.glow(),
+    shape: ButtonShape = IconButtonDefaults.shape(),
+    colors: ButtonColors = IconButtonDefaults.colors(),
+    border: ButtonBorder = IconButtonDefaults.border(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable BoxScope.() -> Unit
+) {
+    Surface(
+        modifier = modifier
+            .semantics { role = Role.Button }
+            .size(IconButtonDefaults.MediumButtonSize),
+        onClick = onClick,
+        enabled = enabled,
+        shape = shape.toClickableSurfaceShape(),
+        color = colors.toClickableSurfaceContainerColor(),
+        contentColor = colors.toClickableSurfaceContentColor(),
+        scale = scale.toClickableSurfaceScale(),
+        border = border.toClickableSurfaceBorder(),
+        glow = glow.toClickableSurfaceGlow(),
+        interactionSource = interactionSource
+    ) {
+        Box(
+            modifier = Modifier.fillMaxSize(),
+            contentAlignment = Alignment.Center,
+            content = content
+        )
+    }
+}
+
+/**
+ * Material Design standard icon button for TV.
+ *
+ * Icon buttons help people take supplementary actions with a single tap. They’re used when a
+ * compact button is required, such as in a toolbar or image list.
+ *
+ * [content] should typically be an [Icon]. If using a custom icon, note that the typical size for
+ * the internal icon is 24 x 24 dp.
+ * This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
+ * guidelines.
+ *
+ * The default text style for internal [Text] components will be set to [Typography.labelLarge].
+ *
+ * @param onClick called when this button is clicked
+ * @param modifier the [Modifier] to be applied to this button
+ * @param enabled controls the enabled state of this button. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services.
+ * @param scale Defines size of the Button relative to its original size
+ * @param glow Shadow to be shown behind the Button.
+ * @param shape Defines the Button's shape.
+ * @param colors Color to be used for background and content of the Button
+ * @param border Defines a border around the Button.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this button. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this button in different states.
+ * @param content the content of the button, typically an [Icon]
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun OutlinedIconButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    scale: ButtonScale = OutlinedIconButtonDefaults.scale(),
+    glow: ButtonGlow = OutlinedIconButtonDefaults.glow(),
+    shape: ButtonShape = OutlinedIconButtonDefaults.shape(),
+    colors: ButtonColors = OutlinedIconButtonDefaults.colors(),
+    border: ButtonBorder = OutlinedIconButtonDefaults.border(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable BoxScope.() -> Unit
+) {
+    Surface(
+        modifier = modifier
+            .semantics { role = Role.Button }
+            .size(OutlinedIconButtonDefaults.MediumButtonSize),
+        onClick = onClick,
+        enabled = enabled,
+        shape = shape.toClickableSurfaceShape(),
+        color = colors.toClickableSurfaceContainerColor(),
+        contentColor = colors.toClickableSurfaceContentColor(),
+        scale = scale.toClickableSurfaceScale(),
+        border = border.toClickableSurfaceBorder(),
+        glow = glow.toClickableSurfaceGlow(),
+        interactionSource = interactionSource
+    ) {
+        Box(
+            modifier = Modifier.fillMaxSize(),
+            contentAlignment = Alignment.Center,
+            content = content
+        )
+    }
+}
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/IconButtonDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/IconButtonDefaults.kt
new file mode 100644
index 0000000..c56fd82
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/IconButtonDefaults.kt
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.interaction.Interaction
+import androidx.annotation.FloatRange
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.dp
+
+@ExperimentalTvMaterial3Api
+object IconButtonDefaults {
+    private val ContainerShape = CircleShape
+
+    /** The size of a small icon inside [IconButton] */
+    val SmallIconSize = 16.dp
+
+    /** The size of a medium icon inside [IconButton] */
+    val MediumIconSize = 20.dp
+
+    /** The size of a large icon inside [IconButton] */
+    val LargeIconSize = 28.dp
+
+    /** The size of a small [IconButton] */
+    val SmallButtonSize = 28.dp
+
+    /** The size of a medium [IconButton]. */
+    val MediumButtonSize = 40.dp
+
+    /** The size of a large [IconButton]. */
+    val LargeButtonSize = 56.dp
+
+    /**
+     * Creates a [ButtonShape] that represents the default container shapes used in a
+     * IconButton.
+     *
+     * @param shape the shape used when the Button is enabled, and has no other [Interaction]s.
+     * @param focusedShape the shape used when the Button is enabled and focused.
+     * @param pressedShape the shape used when the Button is enabled pressed.
+     * @param disabledShape the shape used when the Button is not enabled.
+     * @param focusedDisabledShape the shape used when the Button is not enabled and focused.
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape
+    ) = ButtonShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+
+    /**
+     * Creates a [ButtonColors] that represents the default colors used in a IconButton.
+     *
+     * @param containerColor the container color of this Button when enabled
+     * @param contentColor the content color of this Button when enabled
+     * @param focusedContainerColor the container color of this Button when enabled and focused
+     * @param focusedContentColor the content color of this Button when enabled and focused
+     * @param pressedContainerColor the container color of this Button when enabled and pressed
+     * @param pressedContentColor the content color of this Button when enabled and pressed
+     * @param disabledContainerColor the container color of this Button when not enabled
+     * @param disabledContentColor the content color of this Button when not enabled
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.8f),
+        contentColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = focusedContainerColor,
+        pressedContentColor: Color = focusedContentColor,
+        disabledContainerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.4f),
+        disabledContentColor: Color = contentColor,
+    ) = ButtonColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+    )
+
+    /**
+     * Creates a [ButtonScale] that represents the default scales used in a IconButton.
+     * scales are used to modify the size of a composable in different [Interaction]
+     * states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc.
+     *
+     * @param scale the scale to be used for this Button when enabled
+     * @param focusedScale the scale to be used for this Button when focused
+     * @param pressedScale the scale to be used for this Button when pressed
+     * @param disabledScale the scale to be used for this Button when disabled
+     * @param focusedDisabledScale the scale to be used for this Button when disabled and
+     * focused
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
+    ) = ButtonScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+
+    /**
+     * Creates a [ButtonBorder] that represents the default [Border]s applied on a
+     * IconButton in different [Interaction] states.
+     *
+     * @param border the [Border] to be used for this Button when enabled
+     * @param focusedBorder the [Border] to be used for this Button when focused
+     * @param pressedBorder the [Border] to be used for this Button when pressed
+     * @param disabledBorder the [Border] to be used for this Button when disabled
+     * @param focusedDisabledBorder the [Border] to be used for this Button when disabled and
+     * focused
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border.None,
+        focusedBorder: Border = border,
+        pressedBorder: Border = focusedBorder,
+        disabledBorder: Border = border,
+        focusedDisabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 2.dp,
+                color = MaterialTheme.colorScheme.border.copy(alpha = 0.2f)
+            ),
+            shape = ContainerShape
+        )
+    ) = ButtonBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+
+    /**
+     * Creates a [ButtonGlow] that represents the default [Glow]s used in a IconButton.
+     *
+     * @param glow the Glow behind this Button when enabled
+     * @param focusedGlow the Glow behind this Button when focused
+     * @param pressedGlow the Glow behind this Button when pressed
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow
+    ) = ButtonGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
+
+@ExperimentalTvMaterial3Api
+object OutlinedIconButtonDefaults {
+    private val ContainerShape = CircleShape
+
+    val SmallIconSize = 16.dp
+    val MediumIconSize = 20.dp
+    val LargeIconSize = 28.dp
+
+    /** The size of a small [OutlinedIconButton] */
+    val SmallButtonSize = 28.dp
+
+    /** The size of a medium [OutlinedIconButton]. */
+    val MediumButtonSize = 40.dp
+
+    /** The size of a large [OutlinedIconButton]. */
+    val LargeButtonSize = 56.dp
+
+    /**
+     * Creates a [ButtonShape] that represents the default container shapes used in an
+     * OutlinedIconButton.
+     *
+     * @param shape the shape used when the Button is enabled, and has no other [Interaction]s.
+     * @param focusedShape the shape used when the Button is enabled and focused.
+     * @param pressedShape the shape used when the Button is enabled pressed.
+     * @param disabledShape the shape used when the Button is not enabled.
+     * @param focusedDisabledShape the shape used when the Button is not enabled and focused.
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape
+    ) = ButtonShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+
+    /**
+     * Creates a [ButtonColors] that represents the default colors used in a OutlinedIconButton.
+     *
+     * @param containerColor the container color of this Button when enabled
+     * @param contentColor the content color of this Button when enabled
+     * @param focusedContainerColor the container color of this Button when enabled and focused
+     * @param focusedContentColor the content color of this Button when enabled and focused
+     * @param pressedContainerColor the container color of this Button when enabled and pressed
+     * @param pressedContentColor the content color of this Button when enabled and pressed
+     * @param disabledContainerColor the container color of this Button when not enabled
+     * @param disabledContentColor the content color of this Button when not enabled
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = focusedContainerColor,
+        pressedContentColor: Color = focusedContentColor,
+        disabledContainerColor: Color = containerColor,
+        disabledContentColor: Color = contentColor,
+    ) = ButtonColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+    )
+
+    /**
+     * Creates a [ButtonScale] that represents the default scales used in an
+     * OutlinedIconButton.
+     * scales are used to modify the size of a composable in different [Interaction]
+     * states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc.
+     *
+     * @param scale the scale to be used for this Button when enabled
+     * @param focusedScale the scale to be used for this Button when focused
+     * @param pressedScale the scale to be used for this Button when pressed
+     * @param disabledScale the scale to be used for this Button when disabled
+     * @param focusedDisabledScale the scale to be used for this Button when disabled and
+     * focused
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
+    ) = ButtonScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+
+    /**
+     * Creates a [ButtonBorder] that represents the default [Border]s applied on an
+     * OutlinedIconButton in different [Interaction] states.
+     *
+     * @param border the [Border] to be used for this Button when enabled
+     * @param focusedBorder the [Border] to be used for this Button when focused
+     * @param pressedBorder the [Border] to be used for this Button when pressed
+     * @param disabledBorder the [Border] to be used for this Button when disabled
+     * @param focusedDisabledBorder the [Border] to be used for this Button when disabled and
+     * focused
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border(
+            border = BorderStroke(
+                width = 2.dp,
+                color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.4f)
+            ),
+            shape = ContainerShape
+        ),
+        focusedBorder: Border = Border(
+            border = BorderStroke(width = 2.dp, color = MaterialTheme.colorScheme.onSurface),
+            shape = ContainerShape
+        ),
+        pressedBorder: Border = Border(
+            border = BorderStroke(width = 2.dp, color = MaterialTheme.colorScheme.onSurface),
+            shape = ContainerShape
+        ),
+        disabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 2.dp,
+                color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f)
+            ),
+            shape = ContainerShape
+        ),
+        focusedDisabledBorder: Border = disabledBorder
+    ) = ButtonBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+
+    /**
+     * Creates a [ButtonGlow] that represents the default [Glow]s used in an OutlinedIconButton.
+     *
+     * @param glow the Glow behind this Button when enabled
+     * @param focusedGlow the Glow behind this Button when focused
+     * @param pressedGlow the Glow behind this Button when pressed
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow
+    ) = ButtonGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
index 4d00127..ac34cff 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
@@ -16,10 +16,10 @@
 
 package androidx.tv.material3
 
-import android.view.KeyEvent.KEYCODE_BACK
 import androidx.compose.animation.animateContentSize
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.focusable
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.focusGroup
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxHeight
@@ -35,28 +35,16 @@
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusDirection
-import androidx.compose.ui.focus.FocusManager
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.FocusState
-import androidx.compose.ui.focus.focusProperties
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.key.KeyEventType.Companion.KeyDown
-import androidx.compose.ui.input.key.key
-import androidx.compose.ui.input.key.nativeKeyCode
-import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.input.key.type
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalFocusManager
-import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.LayoutDirection.Ltr
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
 
@@ -96,20 +84,10 @@
     scrimColor: Color = LocalColorScheme.current.scrim.copy(alpha = 0.5f),
     content: @Composable () -> Unit
 ) {
-    val layoutDirection = LocalLayoutDirection.current
     val localDensity = LocalDensity.current
-    val exitDirection =
-        if (layoutDirection == Ltr) FocusDirection.Right else FocusDirection.Left
-    val drawerFocusRequester = remember { FocusRequester() }
     val closedDrawerWidth: MutableState<Dp?> = remember { mutableStateOf(null) }
     val internalDrawerModifier =
         Modifier
-            .modalDrawerNavigation(
-                drawerFocusRequester = drawerFocusRequester,
-                exitDirection = exitDirection,
-                drawerState = drawerState,
-                focusManager = LocalFocusManager.current
-            )
             .zIndex(Float.MAX_VALUE)
             .onSizeChanged {
                 if (closedDrawerWidth.value == null &&
@@ -252,31 +230,7 @@
 }
 
 @Suppress("IllegalExperimentalApiUsage") // TODO (b/233188423): Address before moving to beta
-@OptIn(ExperimentalComposeUiApi::class, ExperimentalTvMaterial3Api::class)
-private fun Modifier.modalDrawerNavigation(
-    drawerFocusRequester: FocusRequester,
-    exitDirection: FocusDirection,
-    drawerState: DrawerState,
-    focusManager: FocusManager
-): Modifier {
-    return this
-        .focusRequester(drawerFocusRequester)
-        .focusProperties {
-            exit = {
-                if (it == exitDirection) {
-                    drawerFocusRequester.requestFocus()
-                    drawerState.setValue(DrawerValue.Closed)
-                    focusManager.moveFocus(it)
-                    FocusRequester.Cancel
-                } else {
-                    FocusRequester.Default
-                }
-            }
-        }
-}
-
-@Suppress("IllegalExperimentalApiUsage") // TODO (b/233188423): Address before moving to beta
-@OptIn(ExperimentalComposeUiApi::class, ExperimentalTvMaterial3Api::class)
+@OptIn(ExperimentalTvMaterial3Api::class, ExperimentalFoundationApi::class)
 @Composable
 private fun DrawerSheet(
     modifier: Modifier = Modifier,
@@ -287,12 +241,7 @@
     // indicates that the drawer has been set to its initial state and has grabbed focus if
     // necessary. Controls whether focus is used to decide the state of the drawer going forward.
     var initializationComplete: Boolean by remember { mutableStateOf(false) }
-    val focusManager = LocalFocusManager.current
     var focusState by remember { mutableStateOf<FocusState?>(null) }
-
-    val isDrawerOpen = drawerState.currentValue == DrawerValue.Open
-    val isDrawerClosed = drawerState.currentValue == DrawerValue.Closed
-
     val focusRequester = remember { FocusRequester() }
     LaunchedEffect(key1 = drawerState.currentValue) {
         if (drawerState.currentValue == DrawerValue.Open && focusState?.hasFocus == false) {
@@ -312,25 +261,12 @@
             .then(modifier)
             .onFocusChanged {
                 focusState = it
-                when {
-                    it.isFocused && isDrawerClosed -> {
-                        drawerState.setValue(DrawerValue.Open)
-                        focusManager.moveFocus(FocusDirection.Enter)
-                    }
 
-                    !it.hasFocus && isDrawerOpen && initializationComplete -> {
-                        drawerState.setValue(DrawerValue.Closed)
-                    }
+                if (initializationComplete) {
+                    drawerState.setValue(if (it.hasFocus) DrawerValue.Open else DrawerValue.Closed)
                 }
             }
-            .onKeyEvent {
-                // Handle back press key event
-                if (it.key.nativeKeyCode == KEYCODE_BACK && it.type == KeyDown) {
-                    focusManager.moveFocus(FocusDirection.Exit)
-                }
-                KeyEventPropagation.ContinuePropagation
-            }
-            .focusable()
+            .focusGroup()
 
     Box(modifier = internalModifier) { content.invoke(drawerState.currentValue) }
 }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Text.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Text.kt
index ac7c7f7..78a455a 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/Text.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Text.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.foundation.text.InlineTextContent
+import androidx.compose.foundation.text.NewTextRendering1_5
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.compositionLocalOf
@@ -105,6 +106,10 @@
     onTextLayout: (TextLayoutResult) -> Unit = {},
     style: TextStyle = LocalTextStyle.current
 ) {
+    // TODO: Remove this flag if the issue (b/277778635) is fixed or it's deprecated
+    @Suppress("DEPRECATION")
+    NewTextRendering1_5 = false
+
     val textColor = color.takeOrElse {
         style.color.takeOrElse {
             LocalContentColor.current
@@ -206,6 +211,10 @@
     onTextLayout: (TextLayoutResult) -> Unit = {},
     style: TextStyle = LocalTextStyle.current
 ) {
+    // TODO: Remove this flag if the issue (b/277778635) is fixed or it's deprecated
+    @Suppress("DEPRECATION")
+    NewTextRendering1_5 = false
+
     val textColor = color.takeOrElse {
         style.color.takeOrElse {
             LocalContentColor.current
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt b/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt
new file mode 100644
index 0000000..30f4d67
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/WideButton.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.NonRestartableComposable
+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.graphics.Color
+import androidx.compose.ui.layout.onPlaced
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.tv.material3.tokens.Elevation
+
+/**
+ * Material Design wide button for TV.
+ *
+ * @param onClick called when this button is clicked
+ * @param modifier the [Modifier] to be applied to this button
+ * @param enabled controls the enabled state of this button. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this button. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this button in different states.
+ * @param background the background to be applied to the [WideButton]
+ * @param scale Defines size of the Button relative to its original size.
+ * @param glow Shadow to be shown behind the Button.
+ * @param shape Defines the Button's shape.
+ * @param contentColor Color to be used for the text content of the Button
+ * @param tonalElevation tonal elevation used to apply a color shift to the button to give the it
+ * higher emphasis
+ * @param border Defines a border around the Button.
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ * @param content the content of the button
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun WideButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    background: @Composable () -> Unit = {
+        WideButtonDefaults.Background(
+            enabled = enabled,
+            interactionSource = interactionSource,
+        )
+    },
+    scale: ButtonScale = WideButtonDefaults.scale(),
+    glow: ButtonGlow = WideButtonDefaults.glow(),
+    shape: ButtonShape = WideButtonDefaults.shape(),
+    contentColor: WideButtonContentColor = WideButtonDefaults.contentColor(),
+    tonalElevation: Dp = Elevation.Level0,
+    border: ButtonBorder = WideButtonDefaults.border(),
+    contentPadding: PaddingValues = WideButtonDefaults.ContentPadding,
+    content: @Composable RowScope.() -> Unit
+) {
+    WideButtonImpl(
+        onClick = onClick,
+        enabled = enabled,
+        scale = scale,
+        glow = glow,
+        shape = shape,
+        contentColor = contentColor,
+        tonalElevation = tonalElevation,
+        border = border,
+        contentPadding = contentPadding,
+        interactionSource = interactionSource,
+        modifier = modifier,
+        background = background,
+        content = content
+    )
+}
+
+/**
+ * Material Design wide button for TV.
+ *
+ * @param onClick called when this button is clicked
+ * @param title the title content of the button, typically a [Text]
+ * @param modifier the [Modifier] to be applied to this button
+ * @param enabled controls the enabled state of this button. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services.
+ * @param icon the leading icon content of the button, typically an [Icon]
+ * @param subtitle the subtitle content of the button, typically a [Text]
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this button. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this button in different states.
+ * @param background the background to be applied to the [WideButton]
+ * @param scale Defines size of the Button relative to its original size.
+ * @param glow Shadow to be shown behind the Button.
+ * @param shape Defines the Button's shape.
+ * @param contentColor Color to be used for the text content of the Button
+ * @param tonalElevation tonal elevation used to apply a color shift to the button to give the it
+ * higher emphasis
+ * @param border Defines a border around the Button.
+ * @param contentPadding the spacing values to apply internally between the container and the
+ * content
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun WideButton(
+    onClick: () -> Unit,
+    title: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    icon: (@Composable () -> Unit)? = null,
+    subtitle: (@Composable () -> Unit)? = null,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    background: @Composable () -> Unit = {
+        WideButtonDefaults.Background(
+            enabled = enabled,
+            interactionSource = interactionSource
+        )
+    },
+    scale: ButtonScale = WideButtonDefaults.scale(),
+    glow: ButtonGlow = WideButtonDefaults.glow(),
+    shape: ButtonShape = WideButtonDefaults.shape(),
+    contentColor: WideButtonContentColor = WideButtonDefaults.contentColor(),
+    tonalElevation: Dp = Elevation.Level0,
+    border: ButtonBorder = WideButtonDefaults.border(),
+    contentPadding: PaddingValues = WideButtonDefaults.ContentPadding,
+) {
+
+    WideButtonImpl(
+        onClick = onClick,
+        enabled = enabled,
+        scale = scale,
+        glow = glow,
+        shape = shape,
+        contentColor = contentColor,
+        tonalElevation = tonalElevation,
+        border = border,
+        contentPadding = contentPadding,
+        interactionSource = interactionSource,
+        modifier = modifier,
+        minHeight = if (subtitle == null)
+            BaseWideButtonDefaults.MinHeight
+        else
+            BaseWideButtonDefaults.MinHeightWithSubtitle,
+        background = background
+    ) {
+        if (icon != null) {
+            icon()
+            Spacer(
+                modifier = Modifier.padding(end = BaseWideButtonDefaults.HorizontalContentGap)
+            )
+        }
+        Column {
+            ProvideTextStyle(
+                value = MaterialTheme.typography.titleMedium,
+                content = {
+                    Box(
+                        modifier = Modifier
+                            .padding(vertical = BaseWideButtonDefaults.VerticalContentGap)
+                    ) {
+                        title()
+                    }
+                }
+            )
+            if (subtitle != null) {
+                ProvideTextStyle(
+                    value = MaterialTheme.typography.bodySmall.copy(
+                        color = LocalContentColor.current.copy(
+                            alpha = BaseWideButtonDefaults.SubtitleAlpha
+                        )
+                    ),
+                    content = subtitle
+                )
+            }
+        }
+    }
+}
+
+@ExperimentalTvMaterial3Api
+@Composable
+private fun WideButtonImpl(
+    onClick: () -> Unit,
+    enabled: Boolean,
+    scale: ButtonScale,
+    glow: ButtonGlow,
+    shape: ButtonShape,
+    contentColor: WideButtonContentColor,
+    tonalElevation: Dp,
+    border: ButtonBorder,
+    contentPadding: PaddingValues,
+    interactionSource: MutableInteractionSource,
+    background: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    minHeight: Dp = BaseWideButtonDefaults.MinHeight,
+    content: @Composable RowScope.() -> Unit
+) {
+    val density = LocalDensity.current
+    var buttonWidth by remember { mutableStateOf(0.dp) }
+    var buttonHeight by remember { mutableStateOf(0.dp) }
+
+    Surface(
+        modifier = modifier.semantics { role = Role.Button },
+        onClick = onClick,
+        enabled = enabled,
+        scale = scale.toClickableSurfaceScale(),
+        glow = glow.toClickableSurfaceGlow(),
+        shape = shape.toClickableSurfaceShape(),
+        color = wideButtonContainerColor(),
+        contentColor = contentColor.toClickableSurfaceContentColor(),
+        tonalElevation = tonalElevation,
+        border = border.toClickableSurfaceBorder(),
+        interactionSource = interactionSource
+    ) {
+        ProvideTextStyle(value = MaterialTheme.typography.labelLarge) {
+            Box(
+                modifier = Modifier
+                    .defaultMinSize(
+                        minWidth = BaseWideButtonDefaults.MinWidth,
+                        minHeight = minHeight,
+                    )
+                    .onPlaced {
+                        with(density) {
+                            buttonWidth = it.size.width.toDp()
+                            buttonHeight = it.size.height.toDp()
+                        }
+                    }
+            ) {
+                Box(modifier = Modifier.size(buttonWidth, buttonHeight)) {
+                    background()
+                }
+
+                Row(
+                    modifier = Modifier
+                        .size(buttonWidth, buttonHeight)
+                        .padding(contentPadding),
+                    verticalAlignment = Alignment.CenterVertically,
+                    content = content
+                )
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Composable
+private fun wideButtonContainerColor() = ClickableSurfaceDefaults.color(
+    color = Color.Transparent,
+    focusedColor = Color.Transparent,
+    pressedColor = Color.Transparent,
+    disabledColor = Color.Transparent,
+)
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/WideButtonDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/WideButtonDefaults.kt
new file mode 100644
index 0000000..07402ff
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/WideButtonDefaults.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.material3
+
+import androidx.annotation.FloatRange
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.dp
+
+internal object BaseWideButtonDefaults {
+    const val SubtitleAlpha = 0.8f
+    val MinWidth = 240.dp
+    val MinHeight = 48.dp
+    val MinHeightWithSubtitle = 64.dp
+    val HorizontalContentGap = 12.dp
+    val VerticalContentGap = 4.dp
+}
+
+@ExperimentalTvMaterial3Api
+object WideButtonDefaults {
+    private val HorizontalPadding = 16.dp
+    private val VerticalPadding = 10.dp
+
+    /** The default content padding used by [WideButton] */
+    internal val ContentPadding = PaddingValues(
+        start = HorizontalPadding,
+        top = VerticalPadding,
+        end = HorizontalPadding,
+        bottom = VerticalPadding
+    )
+
+    private val ContainerShape = RoundedCornerShape(12.dp)
+
+    /**
+     * Default background for a [WideButton]
+     */
+    @Composable
+    fun Background(
+        enabled: Boolean,
+        interactionSource: MutableInteractionSource,
+    ) {
+        val isFocused = interactionSource.collectIsFocusedAsState().value
+        val isPressed = interactionSource.collectIsPressedAsState().value
+
+        val backgroundColor = when {
+            !enabled -> MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.4f)
+            isPressed -> MaterialTheme.colorScheme.onSurface
+            isFocused -> MaterialTheme.colorScheme.onSurface
+            else -> MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.4f)
+        }
+
+        Box(modifier = Modifier
+            .fillMaxSize()
+            .background(backgroundColor))
+    }
+
+    /**
+     * Creates a [ButtonShape] that represents the default container shapes used in a [WideButton]
+     *
+     * @param shape the shape used when the Button is enabled, and has no other [Interaction]s
+     * @param focusedShape the shape used when the Button is enabled and focused
+     * @param pressedShape the shape used when the Button is enabled pressed
+     * @param disabledShape the shape used when the Button is not enabled
+     * @param focusedDisabledShape the shape used when the Button is not enabled and focused
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape
+    ) = ButtonShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+
+    /**
+     * Creates a [WideButtonContentColor] that represents the default content colors used in a
+     * [WideButton]
+     *
+     * @param color the content color of this Button when enabled
+     * @param focusedColor the content color of this Button when enabled and focused
+     * @param pressedColor the content color of this Button when enabled and pressed
+     * @param disabledColor the content color of this Button when not enabled
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun contentColor(
+        color: Color = MaterialTheme.colorScheme.onSurface,
+        focusedColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedColor: Color = focusedColor,
+        disabledColor: Color = color
+    ) = WideButtonContentColor(
+        contentColor = color,
+        focusedContentColor = focusedColor,
+        pressedContentColor = pressedColor,
+        disabledContentColor = disabledColor
+    )
+
+    /**
+     * Creates a [ButtonScale] that represents the default scales used in a [WideButton].
+     * Scale is used to modify the size of a composable in different [Interaction]
+     * states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc.
+     *
+     * @param scale the scale to be used for this Button when enabled
+     * @param focusedScale the scale to be used for this Button when focused
+     * @param pressedScale the scale to be used for this Button when pressed
+     * @param disabledScale the scale to be used for this Button when disabled
+     * @param focusedDisabledScale the scale to be used for this Button when disabled and
+     * focused
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
+    ) = ButtonScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+
+    /**
+     * Creates a [ButtonBorder] that represents the default [Border]s applied on a
+     * [WideButton] in different [Interaction] states
+     *
+     * @param border the [Border] to be used for this Button when enabled
+     * @param focusedBorder the [Border] to be used for this Button when focused
+     * @param pressedBorder the [Border] to be used for this Button when pressed
+     * @param disabledBorder the [Border] to be used for this Button when disabled
+     * @param focusedDisabledBorder the [Border] to be used for this Button when disabled and
+     * focused
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border.None,
+        focusedBorder: Border = border,
+        pressedBorder: Border = focusedBorder,
+        disabledBorder: Border = border,
+        focusedDisabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 2.dp,
+                color = MaterialTheme.colorScheme.border
+            ),
+            inset = 0.dp,
+            shape = ContainerShape
+        )
+    ) = ButtonBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+
+    /**
+     * Creates a [ButtonGlow] that represents the default [Glow]s used in a [WideButton]
+     *
+     * @param glow the Glow behind this Button when enabled
+     * @param focusedGlow the Glow behind this Button when focused
+     * @param pressedGlow the Glow behind this Button when pressed
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow
+    ) = ButtonGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
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 739ee87..201cc38 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
@@ -195,19 +195,19 @@
             return Collections.emptyList();
         }
 
-        Cursor cursor = mContext.getContentResolver()
+        List<PreviewChannel> channels = new ArrayList<>();
+        try (Cursor cursor = mContext.getContentResolver()
                 .query(
                         TvContractCompat.Channels.CONTENT_URI,
                         PreviewChannel.Columns.PROJECTION,
                         null,
                         null,
-                        null);
-
-        List<PreviewChannel> channels = new ArrayList<>();
-        if (cursor != null && cursor.moveToFirst()) {
-            do {
-                channels.add(PreviewChannel.fromCursor(cursor));
-            } while (cursor.moveToNext());
+                        null)) {
+            if (cursor != null && cursor.moveToFirst()) {
+                do {
+                    channels.add(PreviewChannel.fromCursor(cursor));
+                } while (cursor.moveToNext());
+            }
         }
         return channels;
     }
@@ -228,10 +228,15 @@
 
         PreviewChannel channel = null;
         Uri channelUri = TvContractCompat.buildChannelUri(channelId);
-        Cursor cursor = mContext.getContentResolver()
-                .query(channelUri, PreviewChannel.Columns.PROJECTION, null, null, null);
-        if (cursor != null && cursor.moveToFirst()) {
-            channel = PreviewChannel.fromCursor(cursor);
+        try (Cursor cursor = mContext.getContentResolver()
+                .query(channelUri,
+                        PreviewChannel.Columns.PROJECTION,
+                        null,
+                        null,
+                        null)) {
+            if (cursor != null && cursor.moveToFirst()) {
+                channel = PreviewChannel.fromCursor(cursor);
+            }
         }
         return channel;
     }
@@ -416,9 +421,12 @@
 
         PreviewProgram program = null;
         Uri programUri = TvContractCompat.buildPreviewProgramUri(programId);
-        Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
-        if (cursor != null && cursor.moveToFirst()) {
-            program = PreviewProgram.fromCursor(cursor);
+        try (Cursor cursor = mContext.getContentResolver()
+                .query(programUri, null, null, null, null);
+        ) {
+            if (cursor != null && cursor.moveToFirst()) {
+                program = PreviewProgram.fromCursor(cursor);
+            }
         }
         return program;
     }
@@ -492,9 +500,12 @@
 
         WatchNextProgram program = null;
         Uri programUri = TvContractCompat.buildWatchNextProgramUri(programId);
-        Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
-        if (cursor != null && cursor.moveToFirst()) {
-            program = WatchNextProgram.fromCursor(cursor);
+        try (Cursor cursor = mContext.getContentResolver()
+                .query(programUri, null, null, null, null)
+        ) {
+            if (cursor != null && cursor.moveToFirst()) {
+                program = WatchNextProgram.fromCursor(cursor);
+            }
         }
         return program;
     }
diff --git a/viewpager2/integration-tests/testapp/build.gradle b/viewpager2/integration-tests/testapp/build.gradle
index 132a2b0..28dd268 100644
--- a/viewpager2/integration-tests/testapp/build.gradle
+++ b/viewpager2/integration-tests/testapp/build.gradle
@@ -31,6 +31,8 @@
     api(libs.kotlinStdlib)
     implementation(project(":viewpager2:viewpager2"))
     implementation("androidx.activity:activity-ktx:1.2.0")
+    // TODO(b/262583150): force tracing 1.1.0 since its required by androidTest
+    implementation("androidx.tracing:tracing:1.1.0")
     implementation(libs.material) {
         exclude group: "androidx.viewpager2", module: "viewpager2"
     }
diff --git a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/MutableCollectionBaseTest.kt b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/MutableCollectionBaseTest.kt
index 19f1a68..41e039f 100644
--- a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/MutableCollectionBaseTest.kt
+++ b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/MutableCollectionBaseTest.kt
@@ -27,6 +27,7 @@
 import androidx.viewpager2.integration.testapp.R
 import org.hamcrest.CoreMatchers.allOf
 import org.hamcrest.CoreMatchers.equalTo
+import org.junit.Ignore
 import org.junit.Test
 
 /**
@@ -40,6 +41,7 @@
     BaseTest<T>(clazz) {
     override val layoutId get() = R.id.viewPager
 
+    @Ignore("b/276935528")
     @Test
     fun testKeepsState() {
         // increase count of page 1 to 1
@@ -75,6 +77,7 @@
         verifyCount(0)
     }
 
+    @Ignore("b/276935528")
     @Test
     fun testKeepCurrentItemVisibleWithoutDiffUtil() {
         // disable DiffUtil
diff --git a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/PreviewPagesTest.kt b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/PreviewPagesTest.kt
index 61667ad..8d6e988 100644
--- a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/PreviewPagesTest.kt
+++ b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/PreviewPagesTest.kt
@@ -33,6 +33,7 @@
 import androidx.viewpager2.widget.ViewPager2
 import org.hamcrest.CoreMatchers.allOf
 import org.hamcrest.CoreMatchers.equalTo
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -42,6 +43,7 @@
 
     override val layoutId = R.id.view_pager
 
+    @Ignore("b/276935528")
     @Test
     fun test() {
         verifyCurrentPage(0)
diff --git a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/TabLayoutTest.kt b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/TabLayoutTest.kt
index 1ae1ae1..a6b8e6c 100644
--- a/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/TabLayoutTest.kt
+++ b/viewpager2/integration-tests/testapp/src/androidTest/java/androidx/viewpager2/integration/testapp/test/TabLayoutTest.kt
@@ -28,6 +28,7 @@
 import androidx.viewpager2.integration.testapp.cards.Card
 import androidx.viewpager2.integration.testapp.cards.Card.Companion.find
 import androidx.viewpager2.integration.testapp.test.util.onTab
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -40,7 +41,7 @@
     private val tenOfHeartsPage = "10\n♥"
 
     override val layoutId get() = R.id.view_pager
-
+    @Ignore("b/276935528")
     @Test
     fun testTabLayoutIntegration() {
         // test if ViewPager2 follows TabLayout when clicking a tab
diff --git a/wear/compose/compose-foundation/api/current.txt b/wear/compose/compose-foundation/api/current.txt
index c858c7c..224c57f 100644
--- a/wear/compose/compose-foundation/api/current.txt
+++ b/wear/compose/compose-foundation/api/current.txt
@@ -142,6 +142,7 @@
 
   public final class CurvedSizeKt {
     method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
+    method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
     method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
diff --git a/wear/compose/compose-foundation/api/public_plus_experimental_current.txt b/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
index 06a95e9..e73283c 100644
--- a/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-foundation/api/public_plus_experimental_current.txt
@@ -142,6 +142,7 @@
 
   public final class CurvedSizeKt {
     method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
+    method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
     method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
diff --git a/wear/compose/compose-foundation/api/restricted_current.txt b/wear/compose/compose-foundation/api/restricted_current.txt
index c858c7c..224c57f 100644
--- a/wear/compose/compose-foundation/api/restricted_current.txt
+++ b/wear/compose/compose-foundation/api/restricted_current.txt
@@ -142,6 +142,7 @@
 
   public final class CurvedSizeKt {
     method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
+    method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
     method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
     method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
diff --git a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
index 5aaa729..7123f98 100644
--- a/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
+++ b/wear/compose/compose-foundation/samples/src/main/java/androidx/wear/compose/foundation/samples/CurvedWorldSample.kt
@@ -43,6 +43,7 @@
 import androidx.wear.compose.foundation.CurvedTextStyle
 import androidx.wear.compose.foundation.angularGradientBackground
 import androidx.wear.compose.foundation.angularSize
+import androidx.wear.compose.foundation.angularSizeDp
 import androidx.wear.compose.foundation.background
 import androidx.wear.compose.foundation.basicCurvedText
 import androidx.wear.compose.foundation.curvedBox
@@ -51,6 +52,7 @@
 import androidx.wear.compose.foundation.curvedRow
 import androidx.wear.compose.foundation.padding
 import androidx.wear.compose.foundation.radialGradientBackground
+import androidx.wear.compose.foundation.radialSize
 import androidx.wear.compose.foundation.size
 import androidx.wear.compose.foundation.weight
 
@@ -181,7 +183,7 @@
 fun CurvedFixedSize() {
     CurvedLayout(modifier = Modifier.fillMaxSize()) {
         basicCurvedText(
-            "Fixed Size",
+            "45 deg",
             style = {
                 CurvedTextStyle(
                     fontSize = 16.sp,
@@ -192,9 +194,19 @@
                 .background(Color.White)
                 .size(sweepDegrees = 45f, thickness = 40.dp),
         )
-        curvedRow(
-            modifier = CurvedModifier.size(sweepDegrees = 5f, thickness = 30.dp),
-        ) { }
+        basicCurvedText(
+            "40 dp",
+            style = {
+                CurvedTextStyle(
+                    fontSize = 16.sp,
+                    color = Color.Black
+                )
+            },
+            modifier = CurvedModifier
+                .background(Color.Yellow)
+                .radialSize(40.dp)
+                .angularSizeDp(40.dp),
+        )
     }
 }
 
diff --git a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/CurvedSizeTest.kt b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/CurvedSizeTest.kt
index bed1afc..5c7f35a 100644
--- a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/CurvedSizeTest.kt
+++ b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/CurvedSizeTest.kt
@@ -36,6 +36,16 @@
     @Test
     fun equal_nested_sizes_work() = nested_size_test(30f, 20.dp, 30f, 20.dp)
 
+    // TODO: Tests for both .angularSize and .radialSize calls should be added b/275532663
+    @Test
+    fun proper_angular_nested_sizes_in_dp_work() = nested_angular_size_test(60.dp, 30.dp)
+
+    @Test
+    fun inverted_angular_nested_sizes_in_dp_work() = nested_angular_size_test(30.dp, 60.dp)
+
+    @Test
+    fun equal_angular_nested_sizes_in_dp_work() = nested_angular_size_test(30.dp, 30.dp)
+
     private fun nested_size_test(
         angle: Float,
         thickness: Dp,
@@ -69,4 +79,36 @@
             innerCapturedInfo.checkPositionOnParent(0f, 0f)
         }
     }
+
+    private fun nested_angular_size_test(
+        angularSizeInDp: Dp,
+        innerAngularSizeInDp: Dp,
+    ) {
+        val capturedInfo = CapturedInfo()
+        val innerCapturedInfo = CapturedInfo()
+        var angularSizeInPx = 0f
+        var innerAngularSizeInPx = 0f
+        rule.setContent {
+            with(LocalDensity.current) {
+                angularSizeInPx = angularSizeInDp.toPx()
+                innerAngularSizeInPx = innerAngularSizeInDp.toPx()
+            }
+            CurvedLayout {
+                curvedRow(
+                    modifier = CurvedModifier
+                        .spy(capturedInfo)
+                        .angularSizeDp(angularSizeInDp)
+                        .spy(innerCapturedInfo)
+                        .angularSizeDp(innerAngularSizeInDp)
+                ) { }
+            }
+        }
+
+        rule.runOnIdle {
+            capturedInfo.checkAngularDimensionsInPx(angularSizeInPx)
+            innerCapturedInfo.checkParentAngularDimensionsInPx(angularSizeInPx)
+            innerCapturedInfo.checkAngularDimensionsInPx(innerAngularSizeInPx)
+            innerCapturedInfo.checkPositionOnParent(0f, 0f)
+        }
+    }
 }
diff --git a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
index b856252..a8c6b93 100644
--- a/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
+++ b/wear/compose/compose-foundation/src/androidAndroidTest/kotlin/androidx/wear/compose/foundation/SpyModifier.kt
@@ -76,6 +76,18 @@
     }
 }
 
+internal fun CapturedInfo.checkAngularDimensionsInPx(
+    expectedAngularSizeInPx: Float? = null,
+) {
+    if (expectedAngularSizeInPx != null) {
+        Assert.assertEquals(
+            expectedAngularSizeInPx / lastLayoutInfo!!.measureRadius,
+            lastLayoutInfo!!.sweepRadians,
+            FINE_FLOAT_TOLERANCE
+        )
+    }
+}
+
 internal fun CapturedInfo.checkParentDimensions(
     expectedAngleDegrees: Float? = null,
     expectedThicknessPx: Float? = null,
@@ -96,6 +108,18 @@
     }
 }
 
+internal fun CapturedInfo.checkParentAngularDimensionsInPx(
+    expectedAngularSizeInPx: Float? = null,
+) {
+    if (expectedAngularSizeInPx != null) {
+        Assert.assertEquals(
+            expectedAngularSizeInPx / (parentOuterRadius),
+            parentSweepRadians,
+            FINE_FLOAT_TOLERANCE
+        )
+    }
+}
+
 internal fun CapturedInfo.checkPositionOnParent(
     expectedAngularPositionDegrees: Float,
     expectedRadialPositionPx: Float
diff --git a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
index 81a6d18..235a961 100644
--- a/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
+++ b/wear/compose/compose-foundation/src/commonMain/kotlin/androidx/wear/compose/foundation/CurvedSize.kt
@@ -36,13 +36,15 @@
     maxSweepDegrees: Float = 360f,
     minThickness: Dp = 0.dp,
     maxThickness: Dp = Dp.Infinity,
-) = this.then { child -> SizeWrapper(
-    child,
-    minSweepDegrees = minSweepDegrees,
-    maxSweepDegrees = maxSweepDegrees,
-    minThickness = minThickness,
-    maxThickness = maxThickness
-) }
+) = this.then { child ->
+    SweepSizeWrapper(
+        child,
+        minSweepDegrees = minSweepDegrees,
+        maxSweepDegrees = maxSweepDegrees,
+        minThickness = minThickness,
+        maxThickness = maxThickness
+    )
+}
 
 /**
  * Specify the dimensions (sweep and thickness) for the content.
@@ -64,6 +66,23 @@
 /**
  * Specify the sweep (angular size) for the content.
  *
+ * @sample androidx.wear.compose.foundation.samples.CurvedFixedSize
+ *
+ * @param angularWidth Indicates the width (angular size) of the content in DP.
+ */
+public fun CurvedModifier.angularSizeDp(angularWidth: Dp) = this.then { child ->
+    AngularWidthSizeWrapper(
+        child,
+        minAngularWidth = angularWidth,
+        maxAngularWidth = angularWidth,
+        minThickness = 0.dp,
+        maxThickness = Dp.Infinity
+    )
+}
+
+/**
+ * Specify the sweep (angular size) for the content.
+ *
  * @param sweepDegrees Indicates the sweep (angular size) of the content.
  */
 public fun CurvedModifier.angularSize(sweepDegrees: Float) = sizeIn(
@@ -81,17 +100,61 @@
     maxThickness = thickness
 )
 
-internal class SizeWrapper(
+internal class SweepSizeWrapper(
     child: CurvedChild,
     val minSweepDegrees: Float,
     val maxSweepDegrees: Float,
+    minThickness: Dp,
+    maxThickness: Dp,
+) : BaseSizeWrapper(child, minThickness, maxThickness) {
+    override fun CurvedMeasureScope.initializeMeasure(
+        measurables: Iterator<Measurable>
+    ) {
+        baseInitializeMeasure(measurables)
+    }
+
+    override fun calculateSweepRadians(partialLayoutInfo: PartialLayoutInfo): Float =
+        partialLayoutInfo.sweepRadians.coerceIn(
+            minSweepDegrees.toRadians(),
+            maxSweepDegrees.toRadians()
+        )
+}
+
+internal class AngularWidthSizeWrapper(
+    child: CurvedChild,
+    val minAngularWidth: Dp,
+    val maxAngularWidth: Dp,
+    minThickness: Dp,
+    maxThickness: Dp
+) : BaseSizeWrapper(child, minThickness, maxThickness) {
+
+    private var minAngularWidthPx = 0f
+    private var maxAngularWidthPx = 0f
+    override fun CurvedMeasureScope.initializeMeasure(
+        measurables: Iterator<Measurable>
+    ) {
+        minAngularWidthPx = minAngularWidth.toPx()
+        maxAngularWidthPx = maxAngularWidth.toPx()
+
+        baseInitializeMeasure(measurables)
+    }
+
+    override fun calculateSweepRadians(partialLayoutInfo: PartialLayoutInfo): Float =
+        partialLayoutInfo.sweepRadians.coerceIn(
+            minAngularWidthPx / partialLayoutInfo.measureRadius,
+            maxAngularWidthPx / partialLayoutInfo.measureRadius
+        )
+}
+
+internal abstract class BaseSizeWrapper(
+    child: CurvedChild,
     val minThickness: Dp,
     val maxThickness: Dp,
 ) : BaseCurvedChildWrapper(child) {
     private var minThicknessPx = 0f
     private var maxThicknessPx = 0f
 
-    override fun CurvedMeasureScope.initializeMeasure(
+    protected fun CurvedMeasureScope.baseInitializeMeasure(
         measurables: Iterator<Measurable>
     ) {
         minThicknessPx = minThickness.toPx()
@@ -105,26 +168,7 @@
     override fun doEstimateThickness(maxRadius: Float) =
         wrapped.estimateThickness(maxRadius).coerceIn(minThicknessPx, maxThicknessPx)
 
-    override fun doRadialPosition(
-        parentOuterRadius: Float,
-        parentThickness: Float
-    ): PartialLayoutInfo {
-        val partialLayoutInfo = wrapped.radialPosition(
-            parentOuterRadius,
-            estimatedThickness
-        )
-        return PartialLayoutInfo(
-            partialLayoutInfo.sweepRadians.coerceIn(
-                minSweepDegrees.toRadians(),
-                maxSweepDegrees.toRadians()
-            ),
-            parentOuterRadius,
-            thickness = estimatedThickness,
-            measureRadius = partialLayoutInfo.measureRadius +
-                partialLayoutInfo.outerRadius - parentOuterRadius
-        )
-    }
-
+    protected abstract fun calculateSweepRadians(partialLayoutInfo: PartialLayoutInfo): Float
     override fun doAngularPosition(
         parentStartAngleRadians: Float,
         parentSweepRadians: Float,
@@ -137,4 +181,21 @@
         )
         return parentStartAngleRadians
     }
-}
\ No newline at end of file
+
+    override fun doRadialPosition(
+        parentOuterRadius: Float,
+        parentThickness: Float
+    ): PartialLayoutInfo {
+        val partialLayoutInfo = wrapped.radialPosition(
+            parentOuterRadius,
+            estimatedThickness
+        )
+        return PartialLayoutInfo(
+            calculateSweepRadians(partialLayoutInfo),
+            parentOuterRadius,
+            thickness = estimatedThickness,
+            measureRadius = partialLayoutInfo.measureRadius +
+                partialLayoutInfo.outerRadius - parentOuterRadius
+        )
+    }
+}
diff --git a/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/ButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/ButtonScreenshotTest.kt
new file mode 100644
index 0000000..f9f368f
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/ButtonScreenshotTest.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3.test
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import androidx.wear.compose.material3.Button
+import androidx.wear.compose.material3.ButtonDefaults
+import androidx.wear.compose.material3.CenteredText
+import androidx.wear.compose.material3.MaterialTheme
+import androidx.wear.compose.material3.OutlinedButton
+import androidx.wear.compose.material3.SCREENSHOT_GOLDEN_PATH
+import androidx.wear.compose.material3.TEST_TAG
+import androidx.wear.compose.material3.TestIcon
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.setContentWithTheme
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class ButtonScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun button_enabled() = verifyScreenshot() {
+        sampleBaseButton()
+    }
+
+    @Test
+    fun button_disabled() = verifyScreenshot() {
+        sampleBaseButton(enabled = false)
+    }
+
+    @Test
+    fun three_slot_button_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleThreeSlotButton()
+    }
+
+    @Test
+    fun three_slot_button_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleThreeSlotButton()
+    }
+
+    @Test
+    fun button_outlined_enabled() = verifyScreenshot() {
+        sampleOutlinedButton()
+    }
+
+    @Test
+    fun button_outlined_disabled() = verifyScreenshot() {
+        sampleOutlinedButton(enabled = false)
+    }
+
+    @Test
+    fun button_image_background_enabled() = verifyScreenshot {
+        sampleImageBackgroundButton()
+    }
+
+    @Test
+    fun button_image_background_disabled() = verifyScreenshot {
+        sampleImageBackgroundButton(enabled = false)
+    }
+
+    @Composable
+    private fun sampleBaseButton(enabled: Boolean = true) {
+        Button(
+            enabled = enabled,
+            onClick = {},
+            modifier = Modifier.testTag(TEST_TAG)
+        ) {
+            CenteredText("Base Button")
+        }
+    }
+
+    @Composable
+    private fun sampleThreeSlotButton(enabled: Boolean = true) {
+        Button(
+            enabled = enabled,
+            onClick = {},
+            label = { Text("Three Slot Button") },
+            secondaryLabel = { Text("Secondary Label") },
+            icon = { TestIcon() },
+            modifier = Modifier.testTag(TEST_TAG)
+        )
+    }
+
+    @Composable
+    private fun sampleOutlinedButton(enabled: Boolean = true) {
+        OutlinedButton(
+            enabled = enabled,
+            onClick = {},
+            modifier = Modifier.testTag(TEST_TAG)
+        ) {
+            CenteredText("Outlined Button")
+        }
+    }
+
+    @Composable
+    private fun sampleImageBackgroundButton(enabled: Boolean = true) {
+        Button(
+            enabled = enabled,
+            onClick = {},
+            label = { Text("Image Button") },
+            secondaryLabel = { Text("Secondary Label") },
+            colors = ButtonDefaults.imageBackgroundButtonColors(
+                backgroundImagePainter = painterResource(R.drawable.backgroundimage1)
+            ),
+            icon = { TestIcon() },
+            modifier = Modifier.testTag(TEST_TAG)
+        )
+    }
+
+    private fun verifyScreenshot(
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+                Box(
+                    modifier = Modifier
+                        .fillMaxSize()
+                        .background(MaterialTheme.colorScheme.background)
+                ) {
+                    content()
+                }
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
index f412e4f..6642e9a 100644
--- a/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
+++ b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2023 The Android Open Source Project
  *
@@ -21,8 +20,11 @@
 import androidx.annotation.RequiresApi
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.sizeIn
 import androidx.compose.material.icons.Icons
@@ -35,8 +37,8 @@
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.unit.Dp
@@ -61,6 +63,28 @@
     )
 }
 
+@Composable
+fun TestIcon(modifier: Modifier = Modifier, iconLabel: String = "TestIcon") {
+    val testImage = Icons.Outlined.Add
+    Icon(
+        imageVector = testImage,
+        contentDescription = iconLabel,
+        modifier = modifier.testTag(iconLabel)
+    )
+}
+
+@Composable
+fun CenteredText(
+    text: String
+) {
+    Column(
+        modifier = Modifier.fillMaxHeight(),
+        verticalArrangement = Arrangement.Center
+    ) {
+        Text(text)
+    }
+}
+
 fun ComposeContentTestRule.setContentWithThemeForSizeAssertions(
     parentMaxWidth: Dp = BigTestMaxWidth,
     parentMaxHeight: Dp = BigTestMaxHeight,
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt
similarity index 73%
rename from bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
rename to wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt
index 84d9567..0b3bb8d 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
+++ b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-package androidx.bluetooth.integration.testapp.data
+package androidx.wear.compose.material3
 
-import android.os.ParcelUuid
-
-object SampleAdvertiseData {
-    val testUUID: ParcelUuid =
-        ParcelUuid.fromString("00000000-0000-0000-0000-000000000001")
-}
+internal const val SCREENSHOT_GOLDEN_PATH = "wear/compose/material3"
diff --git a/wear/compose/compose-material3/src/androidAndroidTest/res/drawable/backgroundimage1.png b/wear/compose/compose-material3/src/androidAndroidTest/res/drawable/backgroundimage1.png
new file mode 100644
index 0000000..fbb9332
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidAndroidTest/res/drawable/backgroundimage1.png
Binary files differ
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index f1d47a0..478b99e 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -26,8 +26,8 @@
         applicationId "androidx.wear.compose.integration.demos"
         minSdk 25
         targetSdk 30
-        versionCode 13
-        versionName "1.13"
+        versionCode 14
+        versionName "1.14"
         // Change the APK name to match the *testapp regex we use to pick up APKs for testing as
         // part of CI.
         archivesBaseName = "wear-compose-demos-testapp"
diff --git a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
index b14e334..9fe82bca 100644
--- a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
+++ b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
@@ -33,6 +33,7 @@
 import androidx.wear.compose.integration.demos.DemoCategory
 import androidx.wear.compose.integration.demos.WearComposeDemos
 import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,6 +50,7 @@
     @get:Rule
     val rule = createAndroidComposeRule<DemoActivity>()
 
+    @Ignore("b/276935528")
     @Test
     fun navigateThroughAllDemos() {
         // Compose integration-tests are split into batches due to size,
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
index 510f4b4..b21f208 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
@@ -24,6 +24,7 @@
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
 import androidx.annotation.RequiresApi
+import androidx.compose.foundation.focusable
 import androidx.compose.foundation.gestures.FlingBehavior
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.scrollable
@@ -75,14 +76,14 @@
 import androidx.wear.compose.material.Icon
 import androidx.wear.compose.material.MaterialTheme
 import androidx.wear.compose.material.Picker
-import androidx.wear.compose.material.PickerGroupItem
 import androidx.wear.compose.material.PickerDefaults
 import androidx.wear.compose.material.PickerGroup
+import androidx.wear.compose.material.PickerGroupItem
 import androidx.wear.compose.material.PickerGroupState
 import androidx.wear.compose.material.PickerScope
 import androidx.wear.compose.material.PickerState
-import androidx.wear.compose.material.TouchExplorationStateProvider
 import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.TouchExplorationStateProvider
 import androidx.wear.compose.material.rememberPickerGroupState
 import androidx.wear.compose.material.rememberPickerState
 import java.time.LocalDate
@@ -129,7 +130,8 @@
         initialNumberOfOptions = 60,
         initiallySelectedOption = time.second
     )
-    val touchExplorationServicesEnabled by DefaultTouchExplorationStateProvider()
+    val touchExplorationStateProvider = remember { DefaultTouchExplorationStateProvider() }
+    val touchExplorationServicesEnabled by touchExplorationStateProvider
         .touchExplorationState()
 
     MaterialTheme(typography = typography) {
@@ -145,32 +147,25 @@
         val pickerOption = pickerTextOption(textStyle) { "%02d".format(it) }
         val focusRequesterConfirmButton = remember { FocusRequester() }
 
-        val hourContentDescription by remember {
-            derivedStateOf {
-                createDescription(pickerGroupState, hourState.selectedOption, "hours")
+        val hourContentDescription =
+            createDescription(pickerGroupState, hourState.selectedOption, "Hour")
+        val minuteContentDescription =
+            createDescription(pickerGroupState, minuteState.selectedOption, "Minute")
+        val secondContentDescription =
+            createDescription(pickerGroupState, secondState.selectedOption, "Second")
+
+        val onPickerSelected =
+            { current: FocusableElementsTimePicker, next: FocusableElementsTimePicker ->
+                if (pickerGroupState.selectedIndex != current.index) {
+                    pickerGroupState.selectedIndex = current.index
+                } else {
+                    // Double tapping on selected column moves the focus to the next column
+                    pickerGroupState.selectedIndex = next.index
+                    if (next == FocusableElementsTimePicker.CONFIRM_BUTTON) {
+                        focusRequesterConfirmButton.requestFocus()
+                    }
+                }
             }
-        }
-        val minuteContentDescription by remember {
-            derivedStateOf {
-                createDescription(pickerGroupState, minuteState.selectedOption, "minutes")
-            }
-        }
-        val secondContentDescription by remember {
-            derivedStateOf {
-                createDescription(pickerGroupState, secondState.selectedOption, "seconds")
-            }
-        }
-        val onPickerSelected = { curr: FocusableElementsTimePicker,
-            next: FocusableElementsTimePicker ->
-            if (pickerGroupState.selectedIndex != curr.index) {
-                pickerGroupState.selectedIndex = curr.index
-            } else if (next == FocusableElementsTimePicker.CONFIRM_BUTTON) {
-                focusRequesterConfirmButton.requestFocus()
-                pickerGroupState.selectedIndex = next.index
-            } else {
-                pickerGroupState.selectedIndex = next.index
-            }
-        }
 
         Box(modifier = modifier.fillMaxSize()) {
             Column(
@@ -201,13 +196,10 @@
                     horizontalArrangement = Arrangement.Center,
                 ) {
                     PickerGroup(
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = hourState,
                             modifier = Modifier
-                                .size(40.dp, 100.dp).rsbScroll(
-                                    scrollableState = hourState,
-                                    flingBehavior = PickerDefaults.flingBehavior(hourState),
-                                ),
+                                .size(40.dp, 100.dp),
                             onSelected = {
                                 onPickerSelected(
                                     FocusableElementsTimePicker.HOURS,
@@ -217,13 +209,10 @@
                             contentDescription = hourContentDescription,
                             option = pickerOption
                         ),
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = minuteState,
                             modifier = Modifier
-                                .size(40.dp, 100.dp).rsbScroll(
-                                    scrollableState = minuteState,
-                                    flingBehavior = PickerDefaults.flingBehavior(minuteState),
-                                ),
+                                .size(40.dp, 100.dp),
                             onSelected = {
                                 onPickerSelected(
                                     FocusableElementsTimePicker.MINUTES,
@@ -233,13 +222,10 @@
                             contentDescription = minuteContentDescription,
                             option = pickerOption
                         ),
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = secondState,
                             modifier = Modifier
-                                .size(40.dp, 100.dp).rsbScroll(
-                                    scrollableState = secondState,
-                                    flingBehavior = PickerDefaults.flingBehavior(secondState),
-                                ),
+                                .size(40.dp, 100.dp),
                             onSelected = {
                                 onPickerSelected(
                                     FocusableElementsTimePicker.SECONDS,
@@ -251,7 +237,8 @@
                         ),
                         pickerGroupState = pickerGroupState,
                         separator = { Separator(6.dp, textStyle) },
-                        autoCenter = false
+                        autoCenter = false,
+                        touchExplorationStateProvider = touchExplorationStateProvider
                     )
                 }
                 Spacer(
@@ -270,9 +257,11 @@
                     },
                     modifier = Modifier
                         .semantics {
-                            focused = pickerGroupState.selectedIndex > 2
+                            focused = pickerGroupState.selectedIndex ==
+                                FocusableElementsTimePicker.CONFIRM_BUTTON.index
                         }
                         .focusRequester(focusRequesterConfirmButton)
+                        .focusable()
                 ) {
                     Icon(
                         imageVector = Icons.Filled.Check,
@@ -327,10 +316,15 @@
         initiallySelectedOption = time[ChronoField.AMPM_OF_DAY],
         repeatItems = false
     )
-    val touchExplorationServicesEnabled by DefaultTouchExplorationStateProvider()
+
+    val touchExplorationStateProvider = remember { DefaultTouchExplorationStateProvider() }
+
+    val touchExplorationServicesEnabled by touchExplorationStateProvider
         .touchExplorationState()
 
     MaterialTheme(typography = typography) {
+        // When the time picker loads, none of the individual pickers are selected in talkback mode,
+        // otherwise hours picker should be focused.
         val pickerGroupState =
             if (touchExplorationServicesEnabled) {
                 rememberPickerGroupState(FocusableElement12Hour.NONE.index)
@@ -338,30 +332,31 @@
                 rememberPickerGroupState(FocusableElement12Hour.HOURS.index)
             }
         val textStyle = MaterialTheme.typography.display3
-        val pickerOption = pickerTextOption(textStyle) { "%02d".format(it) }
         val focusRequesterConfirmButton = remember { FocusRequester() }
 
-        val hoursContentDescription by remember { derivedStateOf {
-                createDescription12Hour(pickerGroupState, hourState.selectedOption + 1, "hours")
-            } }
-        val minutesContentDescription by remember { derivedStateOf {
-                createDescription12Hour(pickerGroupState, minuteState.selectedOption, "minutes")
-            } }
+        val hoursContentDescription =
+            createDescription12Hour(pickerGroupState, hourState.selectedOption + 1, "Hour")
 
-        val amString = remember {
-            LocalTime.of(6, 0).format(DateTimeFormatter.ofPattern("a"))
+        val minutesContentDescription =
+            createDescription12Hour(pickerGroupState, minuteState.selectedOption, "Minute")
+
+        val amString = "AM"
+        val pmString = "PM"
+        val periodContentDescription by remember(
+            pickerGroupState.selectedIndex,
+            periodState.selectedOption
+        ) {
+            derivedStateOf {
+                if (pickerGroupState.selectedIndex == FocusableElement12Hour.NONE.index) {
+                    "Period"
+                } else if (periodState.selectedOption == 0) {
+                    amString
+                } else pmString
+            }
         }
-        val pmString = remember {
-            LocalTime.of(18, 0).format(DateTimeFormatter.ofPattern("a"))
-        }
-        val periodContentDescription by remember { derivedStateOf {
-                if (pickerGroupState.selectedIndex == FocusableElement12Hour.NONE.index)
-                    createDescription12Hour(pickerGroupState, periodState.selectedOption, "period")
-                else if (periodState.selectedOption == 0)
-                    createDescription12Hour(pickerGroupState, periodState.selectedOption, amString)
-                else createDescription12Hour(pickerGroupState, periodState.selectedOption, pmString)
-            } }
-        Box(modifier = modifier.fillMaxSize()) {
+        Box(
+            modifier = modifier.fillMaxSize()
+        ) {
             Column(
                 modifier = modifier.fillMaxSize(),
                 verticalArrangement = Arrangement.Center,
@@ -376,7 +371,7 @@
                     },
                     color = MaterialTheme.colors.secondary,
                     style = MaterialTheme.typography.button,
-                    maxLines = 1,
+                    maxLines = 1
                 )
                 val weightsToCenterVertically = 0.5f
                 Spacer(
@@ -387,27 +382,25 @@
                 Row(
                     modifier = Modifier.fillMaxWidth(),
                     verticalAlignment = Alignment.CenterVertically,
-                    horizontalArrangement = Arrangement.End,
-                    ) {
+                    horizontalArrangement = Arrangement.Center
+                ) {
                     val doubleTapToNext =
                         { current: FocusableElement12Hour, next: FocusableElement12Hour ->
                             if (pickerGroupState.selectedIndex != current.index) {
                                 pickerGroupState.selectedIndex = current.index
-                            } else if (next == FocusableElement12Hour.CONFIRM_BUTTON) {
-                                focusRequesterConfirmButton.requestFocus()
-                                pickerGroupState.selectedIndex = next.index
                             } else {
+                                // Double tapping on selected column moves the focus to the next column
                                 pickerGroupState.selectedIndex = next.index
+                                if (next == FocusableElement12Hour.CONFIRM_BUTTON) {
+                                    focusRequesterConfirmButton.requestFocus()
+                                }
                             }
                         }
                     Spacer(Modifier.width(16.dp))
                     PickerGroup(
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = hourState,
-                            modifier = Modifier.size(50.dp, 100.dp).rsbScroll(
-                                scrollableState = hourState,
-                                flingBehavior = PickerDefaults.flingBehavior(hourState),
-                            ),
+                            modifier = Modifier.size(48.dp, 100.dp),
                             onSelected = {
                                 doubleTapToNext(
                                     FocusableElement12Hour.HOURS,
@@ -417,13 +410,9 @@
                             contentDescription = hoursContentDescription,
                             option = pickerTextOption(textStyle) { "%02d".format(it + 1) }
                         ),
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = minuteState,
-                            modifier = Modifier.size(50.dp, 100.dp).rsbScroll(
-                                scrollableState = minuteState,
-                                flingBehavior = PickerDefaults.flingBehavior(minuteState),
-                            ),
-
+                            modifier = Modifier.size(48.dp, 100.dp),
                             onSelected = {
                                 doubleTapToNext(
                                     FocusableElement12Hour.MINUTES,
@@ -431,14 +420,11 @@
                                 )
                             },
                             contentDescription = minutesContentDescription,
-                            option = pickerOption
+                            option = pickerTextOption(textStyle) { "%02d".format(it) }
                         ),
-                        PickerGroupItem(
+                        pickerGroupItemWithRSB(
                             pickerState = periodState,
-                            modifier = Modifier.size(64.dp, 100.dp).rsbScroll(
-                                scrollableState = periodState,
-                                flingBehavior = PickerDefaults.flingBehavior(periodState),
-                            ),
+                            modifier = Modifier.size(64.dp, 100.dp),
                             contentDescription = periodContentDescription,
                             onSelected = {
                                 doubleTapToNext(
@@ -446,29 +432,18 @@
                                     FocusableElement12Hour.CONFIRM_BUTTON
                                 )
                             },
-                            option = { optionIndex: Int, pickerSelected: Boolean ->
-                                Box(modifier = Modifier.fillMaxSize()) {
-                                    Text(
-                                        text = if (optionIndex == 0) amString else pmString,
-                                        maxLines = 1,
-                                        style = textStyle,
-                                        color =
-                                        if (pickerSelected) MaterialTheme.colors.secondary
-                                        else MaterialTheme.colors.onBackground,
-                                        modifier = Modifier
-                                            .align(Alignment.Center)
-                                            .wrapContentSize()
-                                    )
-                                }
+                            option = pickerTextOption(textStyle) {
+                                if (it == 0) amString else pmString
                             }
                         ),
                         autoCenter = false,
                         pickerGroupState = pickerGroupState,
                         separator = {
                             if (it == 0) {
-                                Separator(0.dp, textStyle)
-                            }
+                                Separator(2.dp, textStyle)
+                            } else Spacer(Modifier.width(12.dp))
                         },
+                        touchExplorationStateProvider = touchExplorationStateProvider
                     )
                 }
                 Spacer(
@@ -476,28 +451,29 @@
                         .fillMaxWidth()
                         .weight(weightsToCenterVertically)
                 )
-                Button(onClick = {
-                    val confirmedTime = LocalTime.of(
-                        hourState.selectedOption + 1,
-                        minuteState.selectedOption,
-                        0
-                    ).with(ChronoField.AMPM_OF_DAY, periodState.selectedOption.toLong())
-                    onTimeConfirm(confirmedTime)
-                },
+                Button(
+                    onClick = {
+                        val confirmedTime = LocalTime.of(
+                            hourState.selectedOption + 1,
+                            minuteState.selectedOption,
+                            0
+                        ).with(ChronoField.AMPM_OF_DAY, periodState.selectedOption.toLong())
+                        onTimeConfirm(confirmedTime)
+                    },
                     modifier = Modifier
                         .semantics {
                             focused = pickerGroupState.selectedIndex ==
                                 FocusableElement12Hour.CONFIRM_BUTTON.index
                         }
                         .focusRequester(focusRequesterConfirmButton)
-
+                        .focusable()
                 ) {
                     Icon(
                         imageVector = Icons.Filled.Check,
                         contentDescription = "confirm",
                         modifier = Modifier
                             .size(24.dp)
-                            .wrapContentSize(align = Alignment.Center),
+                            .wrapContentSize(align = Alignment.Center)
                     )
                 }
                 Spacer(Modifier.height(8.dp))
@@ -865,7 +841,28 @@
     Spacer(Modifier.width(width))
 }
 
-@Composable fun PickerWithRSB(
+@Composable
+fun pickerGroupItemWithRSB(
+    pickerState: PickerState,
+    modifier: Modifier,
+    contentDescription: String?,
+    onSelected: () -> Unit,
+    readOnlyLabel: @Composable (BoxScope.() -> Unit)? = null,
+    option: @Composable PickerScope.(optionIndex: Int, pickerSelected: Boolean) -> Unit
+) = PickerGroupItem(
+    pickerState = pickerState,
+    modifier = modifier.rsbScroll(
+        scrollableState = pickerState,
+        flingBehavior = PickerDefaults.flingBehavior(pickerState)
+    ),
+    contentDescription = contentDescription,
+    onSelected = onSelected,
+    readOnlyLabel = readOnlyLabel,
+    option = option
+)
+
+@Composable
+fun PickerWithRSB(
     state: PickerState,
     readOnly: Boolean,
     modifier: Modifier,
@@ -955,7 +952,11 @@
 ): String {
     return when (pickerGroupState.selectedIndex) {
         FocusableElementsTimePicker.NONE.index -> label
-        else -> "$selectedValue" + label
+        else -> if (selectedValue == 1) {
+            "$selectedValue $label"
+        } else {
+            "$selectedValue ${label}s"
+        }
     }
 }
 
@@ -965,13 +966,12 @@
     label: String
 ): String {
     return when (pickerGroupState.selectedIndex) {
-        FocusableElement12Hour.HOURS.index -> {
-            "$selectedValue" + label
+        FocusableElement12Hour.NONE.index -> label
+        else -> if (selectedValue == 1) {
+            "$selectedValue $label"
+        } else {
+            "$selectedValue ${label}s"
         }
-        FocusableElement12Hour.MINUTES.index -> {
-            "$selectedValue" + label
-        }
-        else -> label
     }
 }
 
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimatableNode.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimatableNode.java
index ed908a4..b7e8a5a 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimatableNode.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimatableNode.java
@@ -16,12 +16,16 @@
 
 package androidx.wear.protolayout.expression.pipeline;
 
+import static androidx.wear.protolayout.expression.pipeline.AnimationsHelper.maybeSplitToMainAndAuxAnimationSpec;
+
 import android.animation.ArgbEvaluator;
 import android.animation.TypeEvaluator;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.util.Pair;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
 
 /** Data animatable source node within a dynamic data pipeline. */
@@ -29,17 +33,29 @@
     static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
 
     private boolean mIsVisible = false;
-    @NonNull final QuotaAwareAnimator mQuotaAwareAnimator;
+    @NonNull
+    final QuotaAwareAnimator mQuotaAwareAnimator;
 
     protected AnimatableNode(@NonNull QuotaManager quotaManager, @NonNull AnimationSpec spec) {
-        mQuotaAwareAnimator = new QuotaAwareAnimator(quotaManager, spec);
+        this(quotaManager, spec, null);
     }
 
     protected AnimatableNode(
             @NonNull QuotaManager quotaManager,
             @NonNull AnimationSpec spec,
-            @NonNull TypeEvaluator<?> evaluator) {
-        mQuotaAwareAnimator = new QuotaAwareAnimator(quotaManager, spec, evaluator);
+            @Nullable TypeEvaluator<?> evaluator) {
+        // When a reverse duration which is different from forward duration is provided for a
+        // reverse repeated animation, we need to split the spec into two and use
+        // QuotaAwareAnimatorWithAux to create two ValueAnimators internally to achieve the
+        // required effect. For other cases, use QuotaAwareAnimator.
+        Pair<AnimationSpec, AnimationSpec> specs = maybeSplitToMainAndAuxAnimationSpec(spec);
+        if (specs != null) {
+            mQuotaAwareAnimator =
+                    new QuotaAwareAnimatorWithAux(quotaManager, specs.first, specs.second,
+                            evaluator);
+        } else {
+            mQuotaAwareAnimator = new QuotaAwareAnimator(quotaManager, spec, evaluator);
+        }
     }
 
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
@@ -102,7 +118,7 @@
 
     /**
      * Pauses the animator in this node if it has infinite duration, stop it otherwise. Note that
-     * this method has no effect on infinite animators that are not running since Animator#pause()
+     * this method has no effect on infinite animators that are not running since Animator#pause
      * will be a no-op in that case.
      */
     private void stopOrPauseAnimator() {
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimationsHelper.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimationsHelper.java
index 8b6e73c..6208b2a 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimationsHelper.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/AnimationsHelper.java
@@ -23,9 +23,13 @@
 import android.view.animation.PathInterpolator;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.core.util.Pair;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationParameters;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.CubicBezierEasing;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Easing;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.RepeatMode;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Repeatable;
 
@@ -54,40 +58,55 @@
         sRepeatModeForAnimator.put(RepeatMode.REPEAT_MODE_REVERSE, ValueAnimator.REVERSE);
     }
 
-    private AnimationsHelper() {}
-
-    /** Returns the duration from the given {@link AnimationSpec} or default value if not set. */
-    @NonNull
-    public static Duration getDurationOrDefault(@NonNull AnimationSpec spec) {
-        return spec.getDurationMillis() > 0
-                ? Duration.ofMillis(spec.getDurationMillis())
-                : DEFAULT_ANIM_DURATION;
+    private AnimationsHelper() {
     }
 
-    /** Returns the start delay from the given {@link AnimationSpec} or default value if not set. */
+    /** Returns the main duration from the given {@link AnimationSpec} or default value if not
+     * set. */
+    @SuppressWarnings("deprecation") // Make sure the deprecated method is valid for compatibility
     @NonNull
-    public static Duration getStartDelayOrDefault(@NonNull AnimationSpec spec) {
-        return spec.getStartDelayMillis() > 0
-                ? Duration.ofMillis(spec.getStartDelayMillis())
-                : DEFAULT_ANIM_DELAY;
+    public static Duration getMainDurationOrDefault(@NonNull AnimationSpec spec) {
+        return spec.hasAnimationParameters()
+                && spec.getAnimationParameters().getDurationMillis() > 0
+                ? Duration.ofMillis(spec.getAnimationParameters().getDurationMillis())
+                : spec.getDurationMillis() > 0
+                        ? Duration.ofMillis(spec.getDurationMillis())
+                        : DEFAULT_ANIM_DURATION;
+    }
+
+    /** Returns the main delay from the given {@link AnimationSpec} or default value if not set. */
+    @SuppressWarnings("deprecation") // Make sure the deprecated method is valid for compatibility
+    @NonNull
+    public static Duration getMainDelayOrDefault(@NonNull AnimationSpec spec) {
+        return spec.getAnimationParameters().hasDelayMillis()
+                ? Duration.ofMillis(spec.getAnimationParameters().getDelayMillis())
+                : spec.getStartDelayMillis() > 0
+                        ? Duration.ofMillis(spec.getStartDelayMillis())
+                        : DEFAULT_ANIM_DELAY;
     }
 
     /**
-     * Returns the easing converted to the Interpolator from the given {@link AnimationSpec} or
+     * Returns the main easing converted to the Interpolator from the given {@link AnimationSpec} or
      * default value if not set.
      */
+    @SuppressWarnings("deprecation") // Make sure the deprecated method is valid for compatibility
     @NonNull
-    public static Interpolator getInterpolatorOrDefault(@NonNull AnimationSpec spec) {
+    public static Interpolator getMainInterpolatorOrDefault(@NonNull AnimationSpec spec) {
         Interpolator interpolator = DEFAULT_ANIM_INTERPOLATOR;
 
-        if (spec.hasEasing()) {
-            switch (spec.getEasing().getInnerCase()) {
+        Easing easing = null;
+        if (spec.getAnimationParameters().hasEasing()) {
+            easing = spec.getAnimationParameters().getEasing();
+        } else if (spec.hasEasing()) {
+            easing = spec.getEasing();
+        }
+        if (easing != null) {
+            switch (easing.getInnerCase()) {
                 case CUBIC_BEZIER:
-                    if (spec.getEasing().hasCubicBezier()) {
-                        CubicBezierEasing cbe = spec.getEasing().getCubicBezier();
-                        interpolator =
-                                new PathInterpolator(
-                                        cbe.getX1(), cbe.getY1(), cbe.getX2(), cbe.getY2());
+                    if (easing.hasCubicBezier()) {
+                        CubicBezierEasing cbe = easing.getCubicBezier();
+                        interpolator = new PathInterpolator(cbe.getX1(), cbe.getY1(), cbe.getX2(),
+                                cbe.getY2());
                     }
                     break;
                 case INNER_NOT_SET:
@@ -99,7 +118,7 @@
     }
 
     /**
-     * Returns the repeat count from the given {@link AnimationSpec} or default value if not set.
+     * Returns the repeat count from the given {@link AnimationSpec} or default value if not set
      */
     public static int getRepeatCountOrDefault(@NonNull AnimationSpec spec) {
         int repeatCount = DEFAULT_REPEAT_COUNT;
@@ -133,6 +152,145 @@
         return repeatMode;
     }
 
+    // public static Duration getOverrideForwardDurationOrDefault(@NonNull AnimationSpec spec) {...}
+
+    @NonNull
+    public static Duration getOverrideReverseDurationOrDefault(@NonNull AnimationSpec spec) {
+        if (spec.hasRepeatable()) {
+            Repeatable repeatable = spec.getRepeatable();
+            if (repeatable.hasReverseRepeatOverride()) {
+                AnimationParameters reverseParameters = repeatable.getReverseRepeatOverride();
+                return reverseParameters.getDurationMillis() > 0
+                        ? Duration.ofMillis(reverseParameters.getDurationMillis())
+                        : getMainDurationOrDefault(spec);
+            }
+        }
+
+        return getMainDurationOrDefault(spec);
+    }
+
+    /**
+     * Returns true when a reverse duration which is different from forward duration is provided
+     * for a reverse repeated animation.
+     */
+    static boolean hasCustomReverseDuration(@NonNull AnimationSpec spec) {
+        return spec.hasRepeatable()
+                && getRepeatCountOrDefault(spec) != 0
+                && getRepeatModeOrDefault(spec) == ValueAnimator.REVERSE
+                && getOverrideReverseDurationOrDefault(spec).toMillis()
+                != getMainDurationOrDefault(spec).toMillis();
+    }
+
+    static class RepeatDelays {
+        int mForwardRepeatDelay;
+        int mReverseRepeatDelay;
+
+        RepeatDelays(int forwardRepeatDelay, int reverseRepeatDelay) {
+            mForwardRepeatDelay = forwardRepeatDelay;
+            mReverseRepeatDelay = reverseRepeatDelay;
+        }
+    }
+
+    /** Return the pair of forward repeat delay and reverse repeat delay */
+    static RepeatDelays getRepeatDelays(AnimationSpec spec) {
+        int mainDelay = (int) getMainDelayOrDefault(spec).toMillis();
+        int forwardRepeatDelay = mainDelay;
+        int reverseRepeatDelay = mainDelay;
+        int repeatCount = getRepeatCountOrDefault(spec);
+        if (repeatCount > 0 || repeatCount == ValueAnimator.INFINITE) {
+            if (spec.getRepeatable().getForwardRepeatOverride().hasDelayMillis()) {
+                forwardRepeatDelay =
+                        spec.getRepeatable().getForwardRepeatOverride().getDelayMillis();
+            }
+
+            if (getRepeatModeOrDefault(spec) == ValueAnimator.REVERSE
+                    && spec.getRepeatable().getReverseRepeatOverride().hasDelayMillis()) {
+                reverseRepeatDelay =
+                        spec.getRepeatable().getReverseRepeatOverride().getDelayMillis();
+            }
+        }
+
+        return new RepeatDelays(forwardRepeatDelay, reverseRepeatDelay);
+    }
+
+    /**
+     * When a reverse duration which is different from forward duration is provided for a reverse
+     * repeated animation, the spec would be split into main and aux specs. Main spec is for the
+     * animator which require/release quota and plays the forward part of animation; and aux spec is
+     * for the animator which plays the reverse part of animation, syncs with the main animator and
+     * consumes no quota. These two specs are passed into {@link QuotaAwareAnimatorWithAux} to
+     * create
+     * main and aux animators which are played alternately. For other cases, null is returned as no
+     * split would happen.
+     */
+    @Nullable
+    static Pair<AnimationSpec, AnimationSpec> maybeSplitToMainAndAuxAnimationSpec(
+            @NonNull AnimationSpec spec) {
+        if (!hasCustomReverseDuration(spec)) {
+            return null;
+        }
+
+        int forwardDuration = (int) getMainDurationOrDefault(spec).toMillis();
+        int reverseDuration = (int) getOverrideReverseDurationOrDefault(spec).toMillis();
+        Repeatable repeatable = spec.getRepeatable();
+        RepeatDelays repeatDelays = getRepeatDelays(spec);
+
+        Easing easing = null;
+        if (spec.getAnimationParameters().hasEasing()) {
+            easing = spec.getAnimationParameters().getEasing();
+        }
+
+        AnimationParameters.Builder mainParametersBuilder =
+                AnimationParameters.newBuilder()
+                        .setDurationMillis(forwardDuration)
+                        .setDelayMillis((int) getMainDelayOrDefault(spec).toMillis());
+        if (easing != null) {
+            mainParametersBuilder.setEasing(easing);
+        }
+        AnimationSpec mainAnimatorSpec =
+                AnimationSpec.newBuilder()
+                        .setAnimationParameters(mainParametersBuilder.build())
+                        .setRepeatable(
+                                Repeatable.newBuilder()
+                                        .setIterations((repeatable.getIterations() + 1) / 2)
+                                        .setRepeatMode(RepeatMode.REPEAT_MODE_RESTART)
+                                        .setForwardRepeatOverride(
+                                                AnimationParameters.newBuilder()
+                                                        .setDelayMillis(
+                                                                repeatDelays.mReverseRepeatDelay)
+                                                        .build())
+                                        .build())
+                        .build();
+
+        AnimationParameters.Builder auxParametersBuilder =
+                AnimationParameters.newBuilder()
+                        .setDurationMillis(reverseDuration)
+                        // The aux animator plays the reverse part of animation, so wait until
+                        // the first pass of forward animation has run, plus repeat delay if any.
+                        .setDelayMillis(forwardDuration + repeatDelays.mReverseRepeatDelay);
+        if (spec.getRepeatable().getReverseRepeatOverride().hasEasing()) {
+            easing = spec.getRepeatable().getReverseRepeatOverride().getEasing();
+        }
+        if (easing != null) {
+            auxParametersBuilder.setEasing(easing);
+        }
+        AnimationSpec auxAnimatorSpec =
+                AnimationSpec.newBuilder()
+                        .setAnimationParameters(auxParametersBuilder.build())
+                        .setRepeatable(
+                                Repeatable.newBuilder()
+                                        .setIterations(repeatable.getIterations() / 2)
+                                        .setRepeatMode(RepeatMode.REPEAT_MODE_RESTART)
+                                        .setForwardRepeatOverride(
+                                                AnimationParameters.newBuilder()
+                                                        .setDelayMillis(
+                                                                repeatDelays.mForwardRepeatDelay)
+                                                        .build())
+                                        .build())
+                        .build();
+        return Pair.create(mainAnimatorSpec, auxAnimatorSpec);
+    }
+
     /**
      * Sets animation parameters (duration, delay, easing, repeat mode and count) to the given
      * animator. These will be values from the given AnimationSpec if they are set and default
@@ -140,9 +298,9 @@
      */
     public static void applyAnimationSpecToAnimator(
             @NonNull ValueAnimator animator, @NonNull AnimationSpec spec) {
-        animator.setDuration(getDurationOrDefault(spec).toMillis());
-        animator.setStartDelay(getStartDelayOrDefault(spec).toMillis());
-        animator.setInterpolator(getInterpolatorOrDefault(spec));
+        animator.setDuration(getMainDurationOrDefault(spec).toMillis());
+        animator.setStartDelay(getMainDelayOrDefault(spec).toMillis());
+        animator.setInterpolator(getMainInterpolatorOrDefault(spec));
         animator.setRepeatCount(getRepeatCountOrDefault(spec));
         animator.setRepeatMode(getRepeatModeOrDefault(spec));
     }
@@ -154,9 +312,9 @@
      */
     public static void applyAnimationSpecToAnimation(
             @NonNull Animation animation, @NonNull AnimationSpec spec) {
-        animation.setDuration(getDurationOrDefault(spec).toMillis());
-        animation.setStartOffset(getStartDelayOrDefault(spec).toMillis());
-        animation.setInterpolator(getInterpolatorOrDefault(spec));
+        animation.setDuration(getMainDurationOrDefault(spec).toMillis());
+        animation.setStartOffset(getMainDelayOrDefault(spec).toMillis());
+        animation.setInterpolator(getMainInterpolatorOrDefault(spec));
         animation.setRepeatCount(getRepeatCountOrDefault(spec));
         animation.setRepeatMode(getRepeatModeOrDefault(spec));
     }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicDataTransformNode.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicDataTransformNode.java
index f52e536..160d4bc 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicDataTransformNode.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicDataTransformNode.java
@@ -17,8 +17,10 @@
 package androidx.wear.protolayout.expression.pipeline;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import java.util.function.Function;
+import java.util.function.Predicate;
 
 /**
  * Dynamic data node that can perform a transformation from an upstream node. This should be created
@@ -34,8 +36,14 @@
     final Function<I, O> mTransformer;
 
     DynamicDataTransformNode(
+            DynamicTypeValueReceiverWithPreUpdate<O> downstream, Function<I, O> transformer) {
+        this(downstream, transformer, /* validator= */ null);
+    }
+
+    DynamicDataTransformNode(
             DynamicTypeValueReceiverWithPreUpdate<O> downstream,
-            Function<I, O> transformer) {
+            Function<I, O> transformer,
+            @Nullable Predicate<I> validator) {
         this.mDownstream = downstream;
         this.mTransformer = transformer;
 
@@ -49,6 +57,10 @@
 
                     @Override
                     public void onData(@NonNull I newData) {
+                        if (validator != null && !validator.test(newData)) {
+                            mDownstream.onInvalidated();
+                            return;
+                        }
                         O result = mTransformer.apply(newData);
                         mDownstream.onData(result);
                     }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
index 29c80d6..57e7620 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluator.java
@@ -65,6 +65,7 @@
 import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicColor;
 import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicFloat;
 import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicInt32;
+import androidx.wear.protolayout.expression.proto.DynamicProto.ConditionalColorOp;
 import androidx.wear.protolayout.expression.proto.DynamicProto.ConditionalFloatOp;
 import androidx.wear.protolayout.expression.proto.DynamicProto.ConditionalInt32Op;
 import androidx.wear.protolayout.expression.proto.DynamicProto.ConditionalStringOp;
@@ -75,15 +76,11 @@
 import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicInstant;
 import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicInt32;
 import androidx.wear.protolayout.expression.proto.DynamicProto.DynamicString;
-import androidx.wear.protolayout.expression.proto.FixedProto.FixedColor;
-import androidx.wear.protolayout.expression.proto.FixedProto.FixedFloat;
-import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
 
 import java.time.Duration;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.Executor;
 
 /**
@@ -409,41 +406,7 @@
             @NonNull DynamicTypeValueReceiver<Integer> consumer) {
         List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
         bindRecursively(
-                int32Source,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.empty());
-        return new BoundDynamicTypeImpl(resultBuilder);
-    }
-
-    /**
-     * Adds pending expression from the given {@link DynamicInt32} for future evaluation.
-     *
-     * <p>Evaluation of this dynamic type will start when {@link BoundDynamicType#startEvaluation()}
-     * is called on the returned object.
-     *
-     * <p>While the {@link BoundDynamicType} is not destroyed with {@link BoundDynamicType#close()}
-     * by caller, results of evaluation will be sent through the given {@link
-     * DynamicTypeValueReceiver}.
-     *
-     * @param int32Source The given integer dynamic type that should be evaluated.
-     * @param consumer The registered consumer for results of the evaluation. It will be called from
-     *     UI thread.
-     * @param animationFallbackValue The value used if the given {@link DynamicInt32} is animatable
-     *     and animations are disabled.
-     */
-    @NonNull
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public BoundDynamicType bind(
-            @NonNull DynamicInt32 int32Source,
-            @NonNull DynamicTypeValueReceiver<Integer> consumer,
-            int animationFallbackValue) {
-        List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
-        bindRecursively(
-                int32Source,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.of(animationFallbackValue));
+                int32Source, new DynamicTypeValueReceiverOnExecutor<>(consumer), resultBuilder);
         return new BoundDynamicTypeImpl(resultBuilder);
     }
 
@@ -480,33 +443,6 @@
      * @param floatSource The given float dynamic type that should be evaluated.
      * @param consumer The registered consumer for results of the evaluation. It will be called from
      *     UI thread.
-     * @param animationFallbackValue The value used if the given {@link DynamicFloat} is animatable
-     *     and animation are disabled.
-     */
-    @NonNull
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public BoundDynamicType bind(
-            @NonNull DynamicFloat floatSource,
-            @NonNull DynamicTypeValueReceiver<Float> consumer,
-            float animationFallbackValue) {
-        List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
-        bindRecursively(
-                floatSource,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.of(animationFallbackValue));
-        return new BoundDynamicTypeImpl(resultBuilder);
-    }
-
-    /**
-     * Adds pending dynamic type from the given {@link DynamicFloat} for future evaluation.
-     *
-     * <p>Evaluation of this dynamic type will start when {@link BoundDynamicType#startEvaluation()}
-     * is called on the returned object.
-     *
-     * @param floatSource The given float dynamic type that should be evaluated.
-     * @param consumer The registered consumer for results of the evaluation. It will be called from
-     *     UI thread.
      */
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -514,10 +450,7 @@
             @NonNull DynamicFloat floatSource, @NonNull DynamicTypeValueReceiver<Float> consumer) {
         List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
         bindRecursively(
-                floatSource,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.empty());
+                floatSource, new DynamicTypeValueReceiverOnExecutor<>(consumer), resultBuilder);
         return new BoundDynamicTypeImpl(resultBuilder);
     }
 
@@ -562,37 +495,7 @@
             @NonNull DynamicTypeValueReceiver<Integer> consumer) {
         List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
         bindRecursively(
-                colorSource,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.empty());
-        return new BoundDynamicTypeImpl(resultBuilder);
-    }
-
-    /**
-     * Adds pending dynamic type from the given {@link DynamicColor} for future evaluation.
-     *
-     * <p>Evaluation of this dynamic type will start when {@link BoundDynamicType#startEvaluation()}
-     * is called on the returned object.
-     *
-     * @param colorSource The given color dynamic type that should be evaluated.
-     * @param consumer The registered consumer for results of the evaluation. It will be called from
-     *     UI thread.
-     * @param animationFallbackValue The value used if the given {@link DynamicFloat} is animatable
-     *     and animation are disabled.
-     */
-    @NonNull
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public BoundDynamicType bind(
-            @NonNull DynamicColor colorSource,
-            @NonNull DynamicTypeValueReceiver<Integer> consumer,
-            int animationFallbackValue) {
-        List<DynamicDataNode<?>> resultBuilder = new ArrayList<>();
-        bindRecursively(
-                colorSource,
-                new DynamicTypeValueReceiverOnExecutor<>(consumer),
-                resultBuilder,
-                Optional.of(animationFallbackValue));
+                colorSource, new DynamicTypeValueReceiverOnExecutor<>(consumer), resultBuilder);
         return new BoundDynamicTypeImpl(resultBuilder);
     }
 
@@ -752,8 +655,7 @@
                     bindRecursively(
                             stringSource.getInt32FormatOp().getInput(),
                             int32FormatNode.getIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     break;
                 }
             case FLOAT_FORMAT_OP:
@@ -765,8 +667,7 @@
                     bindRecursively(
                             stringSource.getFloatFormatOp().getInput(),
                             floatFormatNode.getIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     break;
                 }
             case STATE_SOURCE:
@@ -831,8 +732,7 @@
     private void bindRecursively(
             @NonNull DynamicInt32 int32Source,
             @NonNull DynamicTypeValueReceiverWithPreUpdate<Integer> consumer,
-            @NonNull List<DynamicDataNode<?>> resultBuilder,
-            @NonNull Optional<Integer> animationFallbackValue) {
+            @NonNull List<DynamicDataNode<?>> resultBuilder) {
         DynamicDataNode<Integer> node;
 
         switch (int32Source.getInnerCase()) {
@@ -855,13 +755,11 @@
                     bindRecursively(
                             int32Source.getArithmeticOperation().getInputLhs(),
                             arithmeticNode.getLhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             int32Source.getArithmeticOperation().getInputRhs(),
                             arithmeticNode.getRhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     break;
                 }
@@ -884,13 +782,11 @@
                     bindRecursively(
                             op.getValueIfTrue(),
                             conditionalNode.getTrueValueIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             op.getValueIfFalse(),
                             conditionalNode.getFalseValueIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     node = conditionalNode;
                     break;
@@ -904,8 +800,7 @@
                     bindRecursively(
                             int32Source.getFloatToInt().getInput(),
                             conversionNode.getIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     break;
                 }
             case DURATION_PART:
@@ -921,58 +816,28 @@
                     break;
                 }
             case ANIMATABLE_FIXED:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedInt32Node(
-                                    FixedInt32.newBuilder()
-                                            .setValue(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
 
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    node =
-                            new AnimatableFixedInt32Node(
-                                    int32Source.getAnimatableFixed(),
-                                    consumer,
-                                    mAnimationQuotaManager);
-                }
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                node =
+                        new AnimatableFixedInt32Node(
+                                int32Source.getAnimatableFixed(), consumer, mAnimationQuotaManager);
                 break;
             case ANIMATABLE_DYNAMIC:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedInt32Node(
-                                    FixedInt32.newBuilder()
-                                            .setValue(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                AnimatableDynamicInt32 dynamicNode = int32Source.getAnimatableDynamic();
+                DynamicAnimatedInt32Node animationNode =
+                        new DynamicAnimatedInt32Node(
+                                consumer, dynamicNode.getAnimationSpec(), mAnimationQuotaManager);
+                node = animationNode;
 
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    AnimatableDynamicInt32 dynamicNode = int32Source.getAnimatableDynamic();
-                    DynamicAnimatedInt32Node animationNode =
-                            new DynamicAnimatedInt32Node(
-                                    consumer,
-                                    dynamicNode.getAnimationSpec(),
-                                    mAnimationQuotaManager);
-                    node = animationNode;
-
-                    bindRecursively(
-                            dynamicNode.getInput(),
-                            animationNode.getInputCallback(),
-                            resultBuilder,
-                            animationFallbackValue);
-                }
+                bindRecursively(
+                        dynamicNode.getInput(), animationNode.getInputCallback(), resultBuilder);
                 break;
             case INNER_NOT_SET:
                 throw new IllegalArgumentException("DynamicInt32 has no inner source set");
@@ -1049,8 +914,7 @@
     private void bindRecursively(
             @NonNull DynamicFloat floatSource,
             @NonNull DynamicTypeValueReceiverWithPreUpdate<Float> consumer,
-            @NonNull List<DynamicDataNode<?>> resultBuilder,
-            @NonNull Optional<Float> animationFallbackValue) {
+            @NonNull List<DynamicDataNode<?>> resultBuilder) {
         DynamicDataNode<?> node;
 
         switch (floatSource.getInnerCase()) {
@@ -1071,13 +935,11 @@
                     bindRecursively(
                             floatSource.getArithmeticOperation().getInputLhs(),
                             arithmeticNode.getLhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             floatSource.getArithmeticOperation().getInputRhs(),
                             arithmeticNode.getRhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     break;
                 }
@@ -1089,8 +951,7 @@
                     bindRecursively(
                             floatSource.getInt32ToFloatOperation().getInput(),
                             toFloatNode.getIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     break;
                 }
             case CONDITIONAL_OP:
@@ -1105,69 +966,37 @@
                     bindRecursively(
                             op.getValueIfTrue(),
                             conditionalNode.getTrueValueIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             op.getValueIfFalse(),
                             conditionalNode.getFalseValueIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     node = conditionalNode;
                     break;
                 }
             case ANIMATABLE_FIXED:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedFloatNode(
-                                    FixedFloat.newBuilder()
-                                            .setValue(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    node =
-                            new AnimatableFixedFloatNode(
-                                    floatSource.getAnimatableFixed(),
-                                    consumer,
-                                    mAnimationQuotaManager);
-                }
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                node =
+                        new AnimatableFixedFloatNode(
+                                floatSource.getAnimatableFixed(), consumer, mAnimationQuotaManager);
                 break;
             case ANIMATABLE_DYNAMIC:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedFloatNode(
-                                    FixedFloat.newBuilder()
-                                            .setValue(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                AnimatableDynamicFloat dynamicNode = floatSource.getAnimatableDynamic();
+                DynamicAnimatedFloatNode animationNode =
+                        new DynamicAnimatedFloatNode(
+                                consumer, dynamicNode.getAnimationSpec(), mAnimationQuotaManager);
+                node = animationNode;
 
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    AnimatableDynamicFloat dynamicNode = floatSource.getAnimatableDynamic();
-                    DynamicAnimatedFloatNode animationNode =
-                            new DynamicAnimatedFloatNode(
-                                    consumer,
-                                    dynamicNode.getAnimationSpec(),
-                                    mAnimationQuotaManager);
-                    node = animationNode;
-
-                    bindRecursively(
-                            dynamicNode.getInput(),
-                            animationNode.getInputCallback(),
-                            resultBuilder,
-                            animationFallbackValue);
-                }
+                bindRecursively(
+                        dynamicNode.getInput(), animationNode.getInputCallback(), resultBuilder);
                 break;
 
             case INNER_NOT_SET:
@@ -1186,8 +1015,7 @@
     private void bindRecursively(
             @NonNull DynamicColor colorSource,
             @NonNull DynamicTypeValueReceiverWithPreUpdate<Integer> consumer,
-            @NonNull List<DynamicDataNode<?>> resultBuilder,
-            @NonNull Optional<Integer> animationFallbackValue) {
+            @NonNull List<DynamicDataNode<?>> resultBuilder) {
         DynamicDataNode<?> node;
 
         switch (colorSource.getInnerCase()) {
@@ -1200,58 +1028,46 @@
                                 mStateStore, colorSource.getStateSource(), consumer);
                 break;
             case ANIMATABLE_FIXED:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedColorNode(
-                                    FixedColor.newBuilder()
-                                            .setArgb(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
-
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    node =
-                            new AnimatableFixedColorNode(
-                                    colorSource.getAnimatableFixed(),
-                                    consumer,
-                                    mAnimationQuotaManager);
-                }
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                node =
+                        new AnimatableFixedColorNode(
+                                colorSource.getAnimatableFixed(), consumer, mAnimationQuotaManager);
                 break;
             case ANIMATABLE_DYNAMIC:
-                if (mAnimationQuotaManager == DISABLED_ANIMATIONS_QUOTA_MANAGER
-                        && animationFallbackValue.isPresent()) {
-                    // Just assign static value if animations are disabled.
-                    node =
-                            new FixedColorNode(
-                                    FixedColor.newBuilder()
-                                            .setArgb(animationFallbackValue.get())
-                                            .build(),
-                                    consumer);
+                // We don't have to check if enableAnimations is true, because if it's false and
+                // we didn't have static value set, constructor has put QuotaManager that don't
+                // have any quota, so animations won't be played and they would jump to the end
+                // value.
+                AnimatableDynamicColor dynamicNode = colorSource.getAnimatableDynamic();
+                DynamicAnimatedColorNode animationNode =
+                        new DynamicAnimatedColorNode(
+                                consumer, dynamicNode.getAnimationSpec(), mAnimationQuotaManager);
+                node = animationNode;
 
-                } else {
-                    // We don't have to check if enableAnimations is true, because if it's false and
-                    // we didn't have static value set, constructor has put QuotaManager that don't
-                    // have any quota, so animations won't be played and they would jump to the end
-                    // value.
-                    AnimatableDynamicColor dynamicNode = colorSource.getAnimatableDynamic();
-                    DynamicAnimatedColorNode animationNode =
-                            new DynamicAnimatedColorNode(
-                                    consumer,
-                                    dynamicNode.getAnimationSpec(),
-                                    mAnimationQuotaManager);
-                    node = animationNode;
+                bindRecursively(
+                        dynamicNode.getInput(), animationNode.getInputCallback(), resultBuilder);
+                break;
+            case CONDITIONAL_OP:
+                ConditionalOpNode<Integer> conditionalNode = new ConditionalOpNode<>(consumer);
 
-                    bindRecursively(
-                            dynamicNode.getInput(),
-                            animationNode.getInputCallback(),
-                            resultBuilder,
-                            animationFallbackValue);
-                }
+                ConditionalColorOp op = colorSource.getConditionalOp();
+                bindRecursively(
+                        op.getCondition(),
+                        conditionalNode.getConditionIncomingCallback(),
+                        resultBuilder);
+                bindRecursively(
+                        op.getValueIfTrue(),
+                        conditionalNode.getTrueValueIncomingCallback(),
+                        resultBuilder);
+                bindRecursively(
+                        op.getValueIfFalse(),
+                        conditionalNode.getFalseValueIncomingCallback(),
+                        resultBuilder);
+
+                node = conditionalNode;
                 break;
             case INNER_NOT_SET:
                 throw new IllegalArgumentException("DynamicColor has no inner source set");
@@ -1288,13 +1104,11 @@
                     bindRecursively(
                             boolSource.getInt32Comparison().getInputLhs(),
                             compNode.getLhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             boolSource.getInt32Comparison().getInputRhs(),
                             compNode.getRhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     break;
                 }
@@ -1334,13 +1148,11 @@
                     bindRecursively(
                             boolSource.getFloatComparison().getInputLhs(),
                             compNode.getLhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
                     bindRecursively(
                             boolSource.getFloatComparison().getInputRhs(),
                             compNode.getRhsIncomingCallback(),
-                            resultBuilder,
-                            Optional.empty());
+                            resultBuilder);
 
                     break;
                 }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
index 3366db4..71ddbd09 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/FloatNodes.java
@@ -38,8 +38,7 @@
         private final DynamicTypeValueReceiverWithPreUpdate<Float> mDownstream;
 
         FixedFloatNode(
-                FixedFloat protoNode,
-                DynamicTypeValueReceiverWithPreUpdate<Float> downstream) {
+                FixedFloat protoNode, DynamicTypeValueReceiverWithPreUpdate<Float> downstream) {
             this.mValue = protoNode.getValue();
             this.mDownstream = downstream;
         }
@@ -53,7 +52,11 @@
         @Override
         @UiThread
         public void init() {
-            mDownstream.onData(mValue);
+            if (Float.isNaN(mValue)) {
+                mDownstream.onInvalidated();
+            } else {
+                mDownstream.onData(mValue);
+            }
         }
 
         @Override
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
index 9d3f3dd..d542928 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/Int32Nodes.java
@@ -47,8 +47,7 @@
         private final DynamicTypeValueReceiverWithPreUpdate<Integer> mDownstream;
 
         FixedInt32Node(
-                FixedInt32 protoNode,
-                DynamicTypeValueReceiverWithPreUpdate<Integer> downstream) {
+                FixedInt32 protoNode, DynamicTypeValueReceiverWithPreUpdate<Integer> downstream) {
             this.mValue = protoNode.getValue();
             this.mDownstream = downstream;
         }
@@ -202,7 +201,8 @@
                             default:
                                 throw new IllegalArgumentException("Unknown rounding mode");
                         }
-                    });
+                    },
+                    x -> x - 1 < Integer.MAX_VALUE && x >= Integer.MIN_VALUE);
         }
     }
 
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimator.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimator.java
index 238286c..6e1349b 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimator.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimator.java
@@ -17,6 +17,7 @@
 package androidx.wear.protolayout.expression.pipeline;
 
 import static androidx.wear.protolayout.expression.pipeline.AnimationsHelper.applyAnimationSpecToAnimator;
+import static androidx.wear.protolayout.expression.pipeline.AnimationsHelper.getRepeatDelays;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -28,8 +29,8 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
-import androidx.annotation.VisibleForTesting;
 import androidx.core.os.HandlerCompat;
+import androidx.wear.protolayout.expression.pipeline.AnimationsHelper.RepeatDelays;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -40,13 +41,13 @@
  * on wrapped {@link Animator} will be replaced.
  */
 class QuotaAwareAnimator {
-    @NonNull private final ValueAnimator mAnimator;
-    @NonNull private final QuotaManager mQuotaManager;
-    @NonNull private final QuotaReleasingAnimatorListener mListener;
-    @NonNull private final Handler mUiHandler;
+    @NonNull protected final ValueAnimator mAnimator;
+    @NonNull protected final QuotaManager mQuotaManager;
+    @NonNull protected final QuotaReleasingAnimatorListener mListener;
+    @NonNull protected final Handler mUiHandler;
     private long mStartDelay = 0;
-    private final Runnable mAcquireQuotaAndAnimateRunnable = this::acquireQuotaAndAnimate;
-    @Nullable private final TypeEvaluator<?> mEvaluator;
+    protected Runnable mAcquireQuotaAndAnimateRunnable = this::acquireQuotaAndAnimate;
+    @Nullable protected final TypeEvaluator<?> mEvaluator;
 
     interface UpdateCallback {
         void onUpdate(@NonNull Object animatedValue);
@@ -64,6 +65,14 @@
             @NonNull QuotaManager quotaManager,
             @NonNull AnimationSpec spec,
             @Nullable TypeEvaluator<?> evaluator) {
+        this(quotaManager, spec, evaluator, false);
+    }
+
+    protected QuotaAwareAnimator(
+            @NonNull QuotaManager quotaManager,
+            @NonNull AnimationSpec spec,
+            @Nullable TypeEvaluator<?> evaluator,
+            boolean alwaysPauseWhenRepeatForward) {
         mQuotaManager = quotaManager;
         mAnimator = new ValueAnimator();
         mUiHandler = new Handler(Looper.getMainLooper());
@@ -74,23 +83,17 @@
         mStartDelay = mAnimator.getStartDelay();
         mAnimator.setStartDelay(0);
 
-        long forwardRepeatDelay = 0;
-        long reverseRepeatDelay = 0;
-        if ((mAnimator.getRepeatCount() > 0 || mAnimator.getRepeatCount() == ValueAnimator.INFINITE)
-                && spec.hasRepeatable()) {
-            forwardRepeatDelay = spec.getRepeatable().getForwardRepeatDelayMillis();
-            reverseRepeatDelay = spec.getRepeatable().getReverseRepeatDelayMillis();
-        }
+        RepeatDelays repeatDelays = getRepeatDelays(spec);
         mListener =
                 new QuotaReleasingAnimatorListener(
                         quotaManager,
                         mAnimator.getRepeatMode(),
-                        forwardRepeatDelay,
-                        reverseRepeatDelay,
+                        repeatDelays.mForwardRepeatDelay,
+                        repeatDelays.mReverseRepeatDelay,
                         mAnimator::resume,
-                        mUiHandler);
+                        mUiHandler,
+                        alwaysPauseWhenRepeatForward);
         mAnimator.addListener(mListener);
-        mAnimator.addPauseListener(mListener);
 
         mEvaluator = evaluator;
     }
@@ -111,12 +114,17 @@
      * @param values A set of values that the animation will animate between over time.
      */
     void setFloatValues(float... values) {
-        mAnimator.cancel();
+        setFloatValues(mAnimator, mEvaluator, values);
+    }
+
+    protected static void setFloatValues(
+            ValueAnimator animator, @Nullable TypeEvaluator<?> evaluator, float... values) {
+        animator.cancel();
         // ValueAnimator#setEvaluator only valid after values are set, and only need to set once.
-        boolean needToSetEvaluator = mAnimator.getValues() == null && mEvaluator != null;
-        mAnimator.setFloatValues(values);
+        boolean needToSetEvaluator = animator.getValues() == null && evaluator != null;
+        animator.setFloatValues(values);
         if (needToSetEvaluator) {
-            mAnimator.setEvaluator(mEvaluator);
+            animator.setEvaluator(evaluator);
         }
     }
 
@@ -126,13 +134,18 @@
      * @param values A set of values that the animation will animate between over time.
      */
     void setIntValues(int... values) {
-        mAnimator.cancel();
+        setIntValues(mAnimator, mEvaluator, values);
+    }
+
+    protected static void setIntValues(
+            ValueAnimator animator, @Nullable TypeEvaluator<?> evaluator, int... values) {
+        animator.cancel();
 
         // ValueAnimator#setEvaluator only valid after values are set, and only need to set once.
-        boolean needToSetEvaluator = mAnimator.getValues() == null && mEvaluator != null;
-        mAnimator.setIntValues(values);
+        boolean needToSetEvaluator = animator.getValues() == null && evaluator != null;
+        animator.setIntValues(values);
         if (needToSetEvaluator) {
-            mAnimator.setEvaluator(mEvaluator);
+            animator.setEvaluator(evaluator);
         }
     }
 
@@ -156,7 +169,7 @@
         }
     }
 
-    private void acquireQuotaAndAnimate() {
+    protected void acquireQuotaAndAnimate() {
         // Only valid after setFloatValues/setIntValues has been called
         if (mAnimator.getValues() == null) {
             return;
@@ -183,16 +196,16 @@
     void tryStartOrResumeInfiniteAnimation() {
         // Early out for finite animation, already running animation or no valid values before any
         // setFloatValues or setIntValues call
-        if (!isInfiniteAnimator() || isRunning() || mAnimator.getValues() == null) {
+        if (!isInfiniteAnimator() || mAnimator.getValues() == null) {
             return;
         }
 
-        if (mAnimator.isPaused()) {
+        if (isPaused()) {
             if (mQuotaManager.tryAcquireQuota(1)) {
                 mListener.mIsUsingQuota.set(true);
                 mAnimator.resume();
             }
-        } else {
+        } else if (!isRunning()) {
             // Infinite animators created when this node was invisible have not started yet.
             tryStartAnimation();
         }
@@ -226,10 +239,14 @@
         // remove pending call to start the animation if any
         mUiHandler.removeCallbacks(mAcquireQuotaAndAnimateRunnable);
         if (mAnimator.getValues() != null) {
-            mAnimator.end();
+            endAnimator();
         }
     }
 
+    protected void endAnimator() {
+        mAnimator.end();
+    }
+
     /** Returns whether the animator in this class has an infinite duration. */
     protected boolean isInfiniteAnimator() {
         return mAnimator.getTotalDuration() == Animator.DURATION_INFINITE;
@@ -237,13 +254,10 @@
 
     /** Returns whether this node has a running animation. */
     boolean isRunning() {
-        return mAnimator.isRunning()
-                // During repeat delay
-                || (mAnimator.isPaused()
-                        && HandlerCompat.hasCallbacks(mUiHandler, mListener.mResumeRepeatRunnable));
+        return mAnimator.isRunning();
     }
 
-    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    /** Returns whether this node has a paused animation. */
     boolean isPaused() {
         return mAnimator.isPaused()
                 // Not during repeat delay
@@ -257,20 +271,30 @@
      * listener will check quota, and if there isn't any available, it will jump to an end of
      * animation.
      */
-    private static final class QuotaReleasingAnimatorListener extends AnimatorListenerAdapter {
-        @NonNull private final QuotaManager mQuotaManager;
+    protected static final class QuotaReleasingAnimatorListener extends AnimatorListenerAdapter {
+        @NonNull
+        private final QuotaManager mQuotaManager;
 
         // We need to keep track of whether the animation has started because pipeline has initiated
-        // and it has received quota, or it is skipped by calling {@link
-        // android.animation.Animator#end()} because no quota is available.
-        @NonNull final AtomicBoolean mIsUsingQuota = new AtomicBoolean(false);
+        // and it has received quota, or it is skipped by calling {@link android.animation
+        // .Animator#end()} because no quota is available.
+        @NonNull
+        final AtomicBoolean mIsUsingQuota = new AtomicBoolean(false);
 
         private final int mRepeatMode;
         private final long mForwardRepeatDelay;
         private final long mReverseRepeatDelay;
-        @NonNull private final Handler mHandler;
-        @NonNull final Runnable mResumeRepeatRunnable;
+        @NonNull
+        private final Handler mHandler;
+        @NonNull
+        Runnable mResumeRepeatRunnable;
         private boolean mIsReverse;
+        /**
+         * Only intended to be true with {@link QuotaAwareAnimatorWithAux} to play main and aux
+         * animators alternately, the pause and resume is still required to swap animators even
+         * without repeat delay.
+         */
+        private final boolean mAlwaysPauseWhenRepeatForward;
 
         QuotaReleasingAnimatorListener(
                 @NonNull QuotaManager quotaManager,
@@ -278,7 +302,8 @@
                 long forwardRepeatDelay,
                 long reverseRepeatDelay,
                 @NonNull Runnable resumeRepeatRunnable,
-                @NonNull Handler uiHandler) {
+                @NonNull Handler uiHandler,
+                boolean alwaysPauseWhenRepeatForward) {
             this.mQuotaManager = quotaManager;
             this.mRepeatMode = repeatMode;
             this.mForwardRepeatDelay = forwardRepeatDelay;
@@ -286,6 +311,16 @@
             this.mResumeRepeatRunnable = resumeRepeatRunnable;
             this.mHandler = uiHandler;
             mIsReverse = false;
+            mAlwaysPauseWhenRepeatForward = alwaysPauseWhenRepeatForward;
+        }
+
+        /**
+         * Only intended to be called from QuotaAwareAnimatorWithAux To play main and aux animators
+         * alternately, resume aux animator after pausing main animator, and resume main animator
+         * after pause aux animator.
+         */
+        void setResumeRunnable(@NonNull Runnable runnable) {
+            mResumeRepeatRunnable = runnable;
         }
 
         @Override
@@ -313,7 +348,7 @@
                 mIsReverse = false;
             }
 
-            if (mForwardRepeatDelay > 0 && !mIsReverse) {
+            if ((mAlwaysPauseWhenRepeatForward || mForwardRepeatDelay > 0) && !mIsReverse) {
                 animation.pause();
                 mHandler.postDelayed(mResumeRepeatRunnable, mForwardRepeatDelay);
             } else if (mReverseRepeatDelay > 0 && mIsReverse) {
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimatorWithAux.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimatorWithAux.java
new file mode 100644
index 0000000..8c8e4a8
--- /dev/null
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/QuotaAwareAnimatorWithAux.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.expression.pipeline;
+
+import static androidx.wear.protolayout.expression.pipeline.AnimationsHelper.applyAnimationSpecToAnimator;
+import static androidx.wear.protolayout.expression.pipeline.AnimationsHelper.getRepeatDelays;
+
+import android.animation.TypeEvaluator;
+import android.animation.ValueAnimator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.os.HandlerCompat;
+import androidx.wear.protolayout.expression.pipeline.AnimationsHelper.RepeatDelays;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
+
+/**
+ * This class handles the animation with custom reverse duration. To have different duration for
+ * forward and reverse animations, two animators are played alternately as follows:
+ *
+ * <p>1. After the start delay, start both animators. 2. Main animator plays forward part of the
+ * animation, aux animator waits for its extra start delay of (forward duration + reverse delay). 3.
+ * Main animator pauses before repeat and calls aux animator to resume after reverse delay. 4. Aux
+ * animator plays reverse part of animation; main animator is paused. 5. Aux animator pauses before
+ * repeat and calls main animator to resume after forward delay. 6. Main animator plays forward part
+ * of the animation; aux animator is paused. 7. .....
+ */
+class QuotaAwareAnimatorWithAux extends QuotaAwareAnimator {
+
+    @NonNull private final QuotaReleasingAnimatorListener mAuxListener;
+    @NonNull private final ValueAnimator mAuxAnimator;
+    private boolean mSuppressForwardUpdate = false;
+    private boolean mSuppressReverseUpdate = false;
+    private final boolean mEndsWithForward;
+
+    QuotaAwareAnimatorWithAux(
+            @NonNull QuotaManager quotaManager,
+            @NonNull AnimationSpec spec,
+            @NonNull AnimationSpec auxSpec,
+            @Nullable TypeEvaluator<?> evaluator) {
+        super(quotaManager, spec, evaluator, /* alwaysPauseWhenRepeatForward= */ true);
+
+        mAuxAnimator = new ValueAnimator();
+        applyAnimationSpecToAnimator(mAuxAnimator, auxSpec);
+        RepeatDelays repeatDelays = getRepeatDelays(auxSpec);
+        mAuxListener =
+                new QuotaReleasingAnimatorListener(
+                        quotaManager,
+                        mAuxAnimator.getRepeatMode(),
+                        repeatDelays.mForwardRepeatDelay,
+                        repeatDelays.mReverseRepeatDelay,
+                        mAnimator::resume,
+                        mUiHandler,
+                        /* alwaysPauseWhenRepeatForward= */ true);
+        mAuxAnimator.addListener(mAuxListener);
+
+        mAcquireQuotaAndAnimateRunnable = this::acquireQuotaAndAnimate;
+        mListener.setResumeRunnable(mAuxAnimator::resume);
+        mEndsWithForward = mAnimator.getRepeatCount() > mAuxAnimator.getRepeatCount();
+    }
+
+    @Override
+    void addUpdateCallback(@NonNull UpdateCallback updateCallback) {
+        // 1. Do not update the animated value when pausing for swap, or there is a jumping frame.
+        // 2. Suppress the update temporarily to avoid assigning one of the end values depending
+        // on the repeating count.
+        mAnimator.addUpdateListener(
+                animation -> {
+                    if (!mSuppressForwardUpdate && !mAnimator.isPaused()) {
+                        updateCallback.onUpdate(animation.getAnimatedValue());
+                    }
+                });
+
+        mAuxAnimator.addUpdateListener(
+                animation -> {
+                    if (!mSuppressReverseUpdate && !mAuxAnimator.isPaused()) {
+                        updateCallback.onUpdate(animation.getAnimatedValue());
+                    }
+                });
+    }
+
+    @Override
+    void setFloatValues(float... values) {
+        super.setFloatValues(values);
+
+        // reverse the value array
+        float temp;
+        for (int i = 0; i < values.length / 2; i++) {
+            temp = values[i];
+            values[i] = values[values.length - 1 - i];
+            values[values.length - 1 - i] = temp;
+        }
+        setFloatValues(mAuxAnimator, mEvaluator, values);
+    }
+
+    @Override
+    void setIntValues(int... values) {
+        super.setIntValues(values);
+
+        // reverse the value array
+        int temp;
+        for (int i = 0; i < values.length / 2; i++) {
+            temp = values[i];
+            values[i] = values[values.length - 1 - i];
+            values[values.length - 1 - i] = temp;
+        }
+        setIntValues(mAuxAnimator, mEvaluator, values);
+    }
+
+    @Override
+    protected void acquireQuotaAndAnimate() {
+        super.acquireQuotaAndAnimate();
+        if (mAnimator.isStarted()) {
+            mAuxAnimator.start();
+        }
+    }
+
+    @Override
+    void tryStartOrResumeInfiniteAnimation() {
+        // Early out for finite animation, already running animation or no valid values before any
+        // setFloatValues or setIntValues call
+        if (!isInfiniteAnimator() || mAnimator.getValues() == null) {
+            return;
+        }
+
+        if (isPaused()) {
+            if (mQuotaManager.tryAcquireQuota(1)) {
+                mListener.mIsUsingQuota.set(true);
+                // to simplify the synchronization after pause, always resume the main animator
+                // and set the aux animator to beginning to be ready to resume before repeating
+                // the main one.
+                mAnimator.resume();
+                mAuxAnimator.setCurrentFraction(0);
+            }
+        } else if (!isRunning()) {
+            // Infinite animators created when this node was invisible have not started yet.
+            tryStartAnimation();
+        }
+    }
+
+    @Override
+    void stopOrPauseAnimator() {
+        super.stopOrPauseAnimator();
+        if (isInfiniteAnimator()) {
+            mAuxAnimator.pause();
+            mUiHandler.removeCallbacks(mAuxListener.mResumeRepeatRunnable);
+        }
+    }
+
+    @Override
+    protected void endAnimator() {
+        mSuppressForwardUpdate = !mEndsWithForward;
+        mSuppressReverseUpdate = mEndsWithForward;
+        mAnimator.end();
+        mAuxAnimator.end();
+        mSuppressForwardUpdate = false;
+        mSuppressReverseUpdate = false;
+    }
+
+    /** Returns whether this node has a running animation. */
+    @Override
+    protected boolean isRunning() {
+        return super.isRunning() || mAuxAnimator.isRunning();
+    }
+
+    @Override
+    protected boolean isPaused() {
+        return super.isPaused()
+                && mAuxAnimator.isPaused()
+                && !HandlerCompat.hasCallbacks(mUiHandler, mAuxListener.mResumeRepeatRunnable);
+    }
+}
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
index 6905235..7bd0f02 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/AnimatableNodeTest.java
@@ -17,7 +17,6 @@
 package androidx.wear.protolayout.expression.pipeline;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.robolectric.Shadows.shadowOf;
 
 import android.animation.TypeEvaluator;
@@ -26,18 +25,21 @@
 
 import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationParameters;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Repeatable;
 
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Range;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(AndroidJUnit4.class)
 public class AnimatableNodeTest {
 
@@ -255,11 +257,104 @@
         assertThat(mUpdateValues).containsExactly(15.0f);
     }
 
+    @Test
+    public void animationWithCustomReverseDuration_animatorWithAux() {
+        QuotaManager quotaManager = new FixedQuotaManagerImpl(1);
+        TestAnimatableNode animNode =
+                new TestAnimatableNode(quotaManager, createAnimationSpec(4, 100, 200, 0, 0));
+        QuotaAwareAnimator animator = animNode.getQuotaAwareAnimator();
+
+        assertThat(animator).isInstanceOf(QuotaAwareAnimatorWithAux.class);
+    }
+
+    @Test
+    public void animationWithCustomReverseDuration_consumeOneQuota() {
+        QuotaManager quotaManager = new FixedQuotaManagerImpl(2);
+        TestAnimatableNode animNode =
+                new TestAnimatableNode(quotaManager, createAnimationSpec(2, 100, 200, 0, 0));
+        animNode.setVisibility(true);
+        QuotaAwareAnimator animator = animNode.getQuotaAwareAnimator();
+        animator.setIntValues(0, 10);
+
+        animNode.startOrSkipAnimator();
+        assertThat(animator.isRunning()).isTrue();
+
+        assertThat(quotaManager.tryAcquireQuota(1)).isTrue();
+        assertThat(quotaManager.tryAcquireQuota(1)).isFalse();
+
+        shadowOf(Looper.getMainLooper()).idle();
+        assertThat(quotaManager.tryAcquireQuota(1)).isTrue();
+    }
+
+    @Test
+    public void animationWithCustomReverseDuration_releaseQuotaWhenInvisible() {
+        QuotaManager quotaManager = new FixedQuotaManagerImpl(1);
+        TestAnimatableNode animNode =
+                new TestAnimatableNode(quotaManager, createAnimationSpec(2, 100, 200, 0, 0));
+        animNode.setVisibility(true);
+        QuotaAwareAnimator animator = animNode.getQuotaAwareAnimator();
+        animator.setIntValues(0, 10);
+
+        animNode.startOrSkipAnimator();
+        assertThat(animator.isRunning()).isTrue();
+        assertThat(quotaManager.tryAcquireQuota(1)).isFalse();
+
+        animNode.setVisibility(false);
+        assertThat(quotaManager.tryAcquireQuota(1)).isTrue();
+    }
+
+    @Test
+    public void animationWithCustomReverseDuration_checkAnimationValues() {
+        mUpdateValues.clear();
+        QuotaManager quotaManager = new FixedQuotaManagerImpl(1);
+        TestAnimatableNode animNode =
+                new TestAnimatableNode(quotaManager, createAnimationSpec(2, 100, 200, 0, 0));
+        animNode.setVisibility(true);
+        QuotaAwareAnimator animator = animNode.getQuotaAwareAnimator();
+
+        float start = 1.0f;
+        float end = 10.0f;
+        animator.setFloatValues(start, end);
+        animator.addUpdateCallback(a -> mUpdateValues.add((float) a));
+        animNode.startOrSkipAnimator();
+        shadowOf(Looper.getMainLooper()).idle();
+
+        for (Float value : mUpdateValues) {
+            assertThat(value).isIn(Range.closed(start, end));
+        }
+        assertThat(mUpdateValues.size()).isGreaterThan(3);
+        assertThat(mUpdateValues.get(0)).isEqualTo(start);
+        assertThat(Iterables.getLast(mUpdateValues)).isEqualTo(start);
+
+        int increasingValueCount = 0;
+        int decreasingValueCount = 0;
+        for (int i = 0; i < mUpdateValues.size() - 2; i++) {
+            if (mUpdateValues.get(i) < mUpdateValues.get(i + 1)) {
+                increasingValueCount++;
+            } else {
+                decreasingValueCount++;
+            }
+        }
+        // reverse duration is double length of forward duration, expecting decreasing value
+        // count about
+        // double of the increasing value count.
+        assertThat(decreasingValueCount).isAtLeast((increasingValueCount - 1) * 2);
+        assertThat(decreasingValueCount).isAtMost((increasingValueCount + 1) * 2);
+    }
+
     static class TestAnimatableNode extends AnimatableNode {
 
         TestAnimatableNode(QuotaAwareAnimator quotaAwareAnimator) {
             super(quotaAwareAnimator);
         }
+
+        TestAnimatableNode(@NonNull QuotaManager quotaManager, @NonNull AnimationSpec spec) {
+            super(quotaManager, spec);
+        }
+
+        QuotaAwareAnimator getQuotaAwareAnimator() {
+            return mQuotaAwareAnimator;
+        }
     }
 
     static class TestQuotaAwareAnimator extends QuotaAwareAnimator {
@@ -270,8 +365,8 @@
         }
 
         @SuppressWarnings("rawtypes")
-        TestQuotaAwareAnimator(
-                @NonNull QuotaManager mQuotaManager, @NonNull TypeEvaluator evaluator) {
+        TestQuotaAwareAnimator(@NonNull QuotaManager mQuotaManager,
+                @NonNull TypeEvaluator evaluator) {
             super(mQuotaManager, AnimationSpec.getDefaultInstance(), evaluator);
         }
 
@@ -280,4 +375,35 @@
             return isInfiniteAnimator;
         }
     }
+
+    @NonNull
+    AnimationSpec createAnimationSpec(
+            int iterations,
+            int forwardDuration,
+            int reverseDuration,
+            int forwardRepeatDelay,
+            int reverseRepeatDelay) {
+        return AnimationSpec.newBuilder()
+                .setAnimationParameters(
+                        AnimationParameters.newBuilder()
+                                .setDurationMillis(forwardDuration)
+                                .build())
+                .setRepeatable(
+                        Repeatable.newBuilder()
+                                .setRepeatMode(
+                                        AnimationParameterProto.RepeatMode.REPEAT_MODE_REVERSE)
+                                .setForwardRepeatOverride(
+                                        AnimationParameters.newBuilder()
+                                                .setDelayMillis(forwardRepeatDelay)
+                                                .build())
+                                .setReverseRepeatOverride(
+                                        AnimationParameters.newBuilder()
+                                                .setDurationMillis(reverseDuration)
+                                                .setDelayMillis(reverseRepeatDelay)
+                                                .build()
+                                )
+                                .setIterations(iterations)
+                                .build())
+                .build();
+    }
 }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
index 5ec9a41..fae40b2 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
@@ -20,12 +20,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.robolectric.Shadows.shadowOf;
+
 import static java.lang.Integer.MAX_VALUE;
 
+import android.graphics.Color;
 import android.icu.util.ULocale;
+import android.os.Looper;
 
 import androidx.annotation.NonNull;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicDuration;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter;
@@ -50,6 +55,7 @@
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 
 @RunWith(ParameterizedRobolectricTestRunner.class)
@@ -83,13 +89,16 @@
             test(DynamicInt32.fromState("state_int_15").div(DynamicFloat.constant(2.0f)), 7.5f),
             test(DynamicInt32.fromState("state_int_15").rem(DynamicFloat.constant(4.5f)), 1.5f),
             test(DynamicFloat.constant(5.0f), 5.0f),
+            testForInvalidValue(DynamicFloat.constant(Float.NaN)),
+            testForInvalidValue(DynamicFloat.constant(Float.NaN).plus(5.0f)),
             test(DynamicFloat.fromState("state_float_1.5"), 1.5f),
             test(DynamicFloat.constant(1234.567f).asInt(), 1234),
             test(DynamicFloat.constant(0.967f).asInt(), 0),
             test(DynamicFloat.constant(-1234.967f).asInt(), -1235),
             test(DynamicFloat.constant(-0.967f).asInt(), -1),
             test(DynamicFloat.constant(Float.MIN_VALUE).asInt(), 0),
-            test(DynamicFloat.constant(Float.MAX_VALUE).asInt(), (int) Float.MAX_VALUE),
+            testForInvalidValue(DynamicFloat.constant(Float.MAX_VALUE).asInt()),
+            testForInvalidValue(DynamicFloat.constant(-Float.MAX_VALUE).asInt()),
             test(DynamicInt32.constant(100).asFloat(), 100.0f),
             test(
                     DynamicInt32.constant(Integer.MIN_VALUE).asFloat(),
@@ -122,10 +131,8 @@
             test(DynamicFloat.constant(0.6f).gte(0.4f), true),
             test(DynamicFloat.constant(0.1234568f).gte(0.1234562f), true),
             test(DynamicBool.constant(true), true),
-            test(DynamicBool.constant(true).isTrue(), true),
-            test(DynamicBool.constant(false).isTrue(), false),
-            test(DynamicBool.constant(true).isFalse(), false),
-            test(DynamicBool.constant(false).isFalse(), true),
+            test(DynamicBool.constant(true).negate(), false),
+            test(DynamicBool.constant(false).negate(), true),
             test(DynamicBool.constant(true).and(DynamicBool.constant(true)), true),
             test(DynamicBool.constant(true).and(DynamicBool.constant(false)), false),
             test(DynamicBool.constant(false).and(DynamicBool.constant(true)), false),
@@ -211,44 +218,71 @@
                             .elseUse(DynamicInt32.constant(10)),
                     10),
             test(
+                    DynamicColor.onCondition(DynamicBool.constant(true))
+                            .use(DynamicColor.constant(Color.BLUE))
+                            .elseUse(DynamicColor.constant(Color.RED)),
+                    Color.BLUE),
+            test(
+                    DynamicColor.onCondition(DynamicBool.constant(false))
+                            .use(DynamicColor.constant(Color.BLUE))
+                            .elseUse(DynamicColor.constant(Color.RED)),
+                    Color.RED),
+            test(
                     DynamicFloat.constant(12.345f)
                             .format(
-                                    FloatFormatter.with()
-                                            .maxFractionDigits(2)
-                                            .minIntegerDigits(4)
-                                            .groupingUsed(true)),
+                                    new FloatFormatter.Builder()
+                                            .setMaxFractionDigits(2)
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "0,012.35"),
             test(
                     DynamicFloat.constant(12.345f)
                             .format(
-                                    FloatFormatter.with()
-                                            .minFractionDigits(4)
-                                            .minIntegerDigits(4)
-                                            .groupingUsed(false)),
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(4)
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(false)
+                                            .build()),
                     "0012.3450"),
             test(
                     DynamicFloat.constant(12.345f)
-                            .format(FloatFormatter.with().maxFractionDigits(1).groupingUsed(true))
+                            .format(
+                                    new FloatFormatter.Builder()
+                                            .setMaxFractionDigits(1)
+                                            .setGroupingUsed(true)
+                                            .build())
                             .concat(DynamicString.constant("°")),
                     "12.3°"),
             test(
                     DynamicFloat.constant(12.345678f)
                             .format(
-                                    FloatFormatter.with()
-                                            .minFractionDigits(4)
-                                            .maxFractionDigits(2)
-                                            .groupingUsed(true)),
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(4)
+                                            .setMaxFractionDigits(2)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "12.3457"),
             test(
                     DynamicFloat.constant(12.345678f)
-                            .format(FloatFormatter.with().minFractionDigits(2).groupingUsed(true)),
+                            .format(
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(2)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "12.346"),
-            test(DynamicFloat.constant(12.3456f).format(FloatFormatter.with()), "12.346"),
+            test(
+                    DynamicFloat.constant(12.3456f).format(new FloatFormatter.Builder().build()),
+                    "12.346"),
             test(
                     DynamicInt32.constant(12)
-                            .format(IntFormatter.with().minIntegerDigits(4).groupingUsed(true)),
+                            .format(
+                                    new IntFormatter.Builder()
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "0,012"),
-            test(DynamicInt32.constant(12).format(IntFormatter.with()), "12")
+            test(DynamicInt32.constant(12).format(new IntFormatter.Builder().build()), "12")
         };
         ImmutableList.Builder<Object[]> immutableListBuilder = new ImmutableList.Builder<>();
         for (DynamicTypeEvaluatorTest.TestCase<?> testCase : testCases) {
@@ -304,13 +338,25 @@
                 expectedValue);
     }
 
+    private static DynamicTypeEvaluatorTest.TestCase<Integer> test(
+            DynamicColor bindUnderTest, Integer expectedValue) {
+        return new DynamicTypeEvaluatorTest.TestCase<>(
+                bindUnderTest.toDynamicColorProto().toString(),
+                (evaluator, cb) ->
+                        evaluator
+                                .bind(bindUnderTest, new MainThreadExecutor(), cb)
+                                .startEvaluation(),
+                expectedValue);
+    }
+
     private static DynamicTypeEvaluatorTest.TestCase<Instant> test(
             DynamicInstant bindUnderTest, Instant instant) {
         return new DynamicTypeEvaluatorTest.TestCase<>(
                 bindUnderTest.toDynamicInstantProto().toString(),
-                (evaluator, cb) -> {
-                    evaluator.bind(bindUnderTest, new MainThreadExecutor(), cb).startEvaluation();
-                },
+                (evaluator, cb) ->
+                        evaluator
+                                .bind(bindUnderTest, new MainThreadExecutor(), cb)
+                                .startEvaluation(),
                 instant);
     }
 
@@ -336,6 +382,26 @@
                 expectedValue);
     }
 
+    private static DynamicTypeEvaluatorTest.TestCase<Integer> testForInvalidValue(
+            DynamicInt32 bindUnderTest) {
+        return new DynamicTypeEvaluatorTest.TestCase<>(
+                bindUnderTest.toDynamicInt32Proto().toString(),
+                (evaluator, cb) ->
+                        evaluator
+                                .bind(bindUnderTest, new MainThreadExecutor(), cb)
+                                .startEvaluation());
+    }
+
+    private static DynamicTypeEvaluatorTest.TestCase<Float> testForInvalidValue(
+            DynamicFloat bindUnderTest) {
+        return new DynamicTypeEvaluatorTest.TestCase<>(
+                bindUnderTest.toDynamicFloatProto().toString(),
+                (evaluator, cb) ->
+                        evaluator
+                                .bind(bindUnderTest, new MainThreadExecutor(), cb)
+                                .startEvaluation());
+    }
+
     private static class TestCase<T> {
         private final String mName;
         private final BiConsumer<DynamicTypeEvaluator, DynamicTypeValueReceiver<T>>
@@ -351,8 +417,18 @@
             this.mExpectedValue = expectedValue;
         }
 
+        /** Creates a test case for an expression which expects to result in invalid value. */
+        TestCase(
+                String name,
+                BiConsumer<DynamicTypeEvaluator, DynamicTypeValueReceiver<T>> expressionEvaluator) {
+            this.mName = name;
+            this.mExpressionEvaluator = expressionEvaluator;
+            this.mExpectedValue = null;
+        }
+
         public void runTest(DynamicTypeEvaluator evaluator) {
             List<T> results = new ArrayList<>();
+            AtomicInteger invalidatedCalls = new AtomicInteger(0);
 
             DynamicTypeValueReceiver<T> callback =
                     new DynamicTypeValueReceiver<T>() {
@@ -362,16 +438,25 @@
                         }
 
                         @Override
-                        public void onInvalidated() {}
+                        public void onInvalidated() {
+                            invalidatedCalls.incrementAndGet();
+                        }
                     };
 
             this.mExpressionEvaluator.accept(evaluator, callback);
+            shadowOf(Looper.getMainLooper()).idle();
 
-            assertThat(results).hasSize(1);
-            assertThat(results).containsExactly(mExpectedValue);
+            if (mExpectedValue != null) {
+                // Test expects an actual value.
+                assertThat(results).hasSize(1);
+                assertThat(results).containsExactly(mExpectedValue);
+            } else {
+                // Test expects an invalid value.
+                assertThat(results).isEmpty();
+                assertThat(invalidatedCalls.get()).isEqualTo(1);
+            }
         }
 
-        @NonNull
         @Override
         public String toString() {
             return mName + " = " + mExpectedValue;
diff --git a/wear/protolayout/protolayout-expression/api/current.txt b/wear/protolayout/protolayout-expression/api/current.txt
index 541f553..81a51e5 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -7,21 +7,31 @@
     field public static final int REPEAT_MODE_UNKNOWN = 0; // 0x0
   }
 
-  public static final class AnimationParameterBuilders.AnimationSpec {
+  public static final class AnimationParameterBuilders.AnimationParameters {
+    method public int getDelayMillis();
     method public int getDurationMillis();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing? getEasing();
+  }
+
+  public static final class AnimationParameterBuilders.AnimationParameters.Builder {
+    ctor public AnimationParameterBuilders.AnimationParameters.Builder();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters build();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDurationMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+  }
+
+  public static final class AnimationParameterBuilders.AnimationSpec {
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getAnimationParameters();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable? getRepeatable();
-    method public int getStartDelayMillis();
   }
 
   public static final class AnimationParameterBuilders.AnimationSpec.Builder {
     ctor public AnimationParameterBuilders.AnimationSpec.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setDurationMillis(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setAnimationParameters(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setInfiniteRepeatable(int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setRepeatable(androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setStartDelayMillis(int);
   }
 
   public static final class AnimationParameterBuilders.CubicBezierEasing implements androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing {
@@ -52,20 +62,20 @@
   }
 
   public static final class AnimationParameterBuilders.Repeatable {
-    method public int getForwardRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getForwardRepeatOverride();
     method public int getIterations();
     method public int getRepeatMode();
-    method public int getReverseRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getReverseRepeatOverride();
     method public boolean hasInfiniteIteration();
   }
 
   public static final class AnimationParameterBuilders.Repeatable.Builder {
     ctor public AnimationParameterBuilders.Repeatable.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setIterations(@IntRange(from=1) int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setRepeatMode(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
   }
 
   public class ConditionScopes {
@@ -89,8 +99,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool constant(boolean);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromState(String);
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isFalse();
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isTrue();
+    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool negate();
     method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool or(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicBoolByteArray();
   }
@@ -105,6 +114,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor constant(@ColorInt int);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromState(String);
+    method public static androidx.wear.protolayout.expression.ConditionScopes.ConditionScope<androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor!,java.lang.Integer!> onCondition(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicColorByteArray();
   }
 
@@ -166,11 +176,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -231,9 +249,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
index fbf68ba..a95e751 100644
--- a/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
@@ -7,21 +7,31 @@
     field public static final int REPEAT_MODE_UNKNOWN = 0; // 0x0
   }
 
-  public static final class AnimationParameterBuilders.AnimationSpec {
+  public static final class AnimationParameterBuilders.AnimationParameters {
+    method public int getDelayMillis();
     method public int getDurationMillis();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing? getEasing();
+  }
+
+  public static final class AnimationParameterBuilders.AnimationParameters.Builder {
+    ctor public AnimationParameterBuilders.AnimationParameters.Builder();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters build();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDurationMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+  }
+
+  public static final class AnimationParameterBuilders.AnimationSpec {
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getAnimationParameters();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable? getRepeatable();
-    method public int getStartDelayMillis();
   }
 
   public static final class AnimationParameterBuilders.AnimationSpec.Builder {
     ctor public AnimationParameterBuilders.AnimationSpec.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setDurationMillis(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setAnimationParameters(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setInfiniteRepeatable(int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setRepeatable(androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setStartDelayMillis(int);
   }
 
   public static final class AnimationParameterBuilders.CubicBezierEasing implements androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing {
@@ -52,20 +62,20 @@
   }
 
   public static final class AnimationParameterBuilders.Repeatable {
-    method public int getForwardRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getForwardRepeatOverride();
     method public int getIterations();
     method public int getRepeatMode();
-    method public int getReverseRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getReverseRepeatOverride();
     method public boolean hasInfiniteIteration();
   }
 
   public static final class AnimationParameterBuilders.Repeatable.Builder {
     ctor public AnimationParameterBuilders.Repeatable.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setIterations(@IntRange(from=1) int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setRepeatMode(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
   }
 
   public class ConditionScopes {
@@ -89,8 +99,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool constant(boolean);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromState(String);
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isFalse();
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isTrue();
+    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool negate();
     method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool or(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicBoolByteArray();
   }
@@ -105,6 +114,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor constant(@ColorInt int);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromState(String);
+    method public static androidx.wear.protolayout.expression.ConditionScopes.ConditionScope<androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor!,java.lang.Integer!> onCondition(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicColorByteArray();
   }
 
@@ -166,11 +176,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -231,9 +249,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/api/restricted_current.txt b/wear/protolayout/protolayout-expression/api/restricted_current.txt
index 541f553..81a51e5 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -7,21 +7,31 @@
     field public static final int REPEAT_MODE_UNKNOWN = 0; // 0x0
   }
 
-  public static final class AnimationParameterBuilders.AnimationSpec {
+  public static final class AnimationParameterBuilders.AnimationParameters {
+    method public int getDelayMillis();
     method public int getDurationMillis();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing? getEasing();
+  }
+
+  public static final class AnimationParameterBuilders.AnimationParameters.Builder {
+    ctor public AnimationParameterBuilders.AnimationParameters.Builder();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters build();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setDurationMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+  }
+
+  public static final class AnimationParameterBuilders.AnimationSpec {
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getAnimationParameters();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable? getRepeatable();
-    method public int getStartDelayMillis();
   }
 
   public static final class AnimationParameterBuilders.AnimationSpec.Builder {
     ctor public AnimationParameterBuilders.AnimationSpec.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setDurationMillis(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setEasing(androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setAnimationParameters(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setInfiniteRepeatable(int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setRepeatable(androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec.Builder setStartDelayMillis(int);
   }
 
   public static final class AnimationParameterBuilders.CubicBezierEasing implements androidx.wear.protolayout.expression.AnimationParameterBuilders.Easing {
@@ -52,20 +62,20 @@
   }
 
   public static final class AnimationParameterBuilders.Repeatable {
-    method public int getForwardRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getForwardRepeatOverride();
     method public int getIterations();
     method public int getRepeatMode();
-    method public int getReverseRepeatDelayMillis();
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters? getReverseRepeatOverride();
     method public boolean hasInfiniteIteration();
   }
 
   public static final class AnimationParameterBuilders.Repeatable.Builder {
     ctor public AnimationParameterBuilders.Repeatable.Builder();
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable build();
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setForwardRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setIterations(@IntRange(from=1) int);
     method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setRepeatMode(int);
-    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatDelayMillis(int);
+    method public androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable.Builder setReverseRepeatOverride(androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters);
   }
 
   public class ConditionScopes {
@@ -89,8 +99,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool constant(boolean);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool fromState(String);
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isFalse();
-    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool isTrue();
+    method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool negate();
     method public default androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool or(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicBoolByteArray();
   }
@@ -105,6 +114,7 @@
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor constant(@ColorInt int);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromByteArray(byte[]);
     method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor fromState(String);
+    method public static androidx.wear.protolayout.expression.ConditionScopes.ConditionScope<androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor!,java.lang.Integer!> onCondition(androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool);
     method public default byte[] toDynamicColorByteArray();
   }
 
@@ -166,11 +176,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -231,9 +249,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
index 7c031e7..9686eac 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/AnimationParameterBuilders.java
@@ -124,32 +124,14 @@
     }
 
     /**
-     * Gets the duration of the animation in milliseconds.
-     *
-     * @since 1.2
-     */
-    public int getDurationMillis() {
-      return mImpl.getDurationMillis();
-    }
-
-    /**
-     * Gets the delay to start the animation in milliseconds.
-     *
-     * @since 1.2
-     */
-    public int getStartDelayMillis() {
-      return mImpl.getStartDelayMillis();
-    }
-
-    /**
-     * Gets the easing to be used for adjusting an animation's fraction.
+     * Gets animation parameters including duration, easing and repeat delay.
      *
      * @since 1.2
      */
     @Nullable
-    public Easing getEasing() {
-      if (mImpl.hasEasing()) {
-        return AnimationParameterBuilders.easingFromProto(mImpl.getEasing());
+    public AnimationParameters getAnimationParameters() {
+      if (mImpl.hasAnimationParameters()) {
+        return AnimationParameters.fromProto(mImpl.getAnimationParameters());
       } else {
         return null;
       }
@@ -215,12 +197,8 @@
     @NonNull
     public String toString() {
       return "AnimationSpec{"
-          + "durationMillis="
-          + getDurationMillis()
-          + ", startDelayMillis="
-          + getStartDelayMillis()
-          + ", easing="
-          + getEasing()
+          + "animationParameters="
+          + getAnimationParameters()
           + ", repeatable="
           + getRepeatable()
           + "}";
@@ -235,40 +213,15 @@
       public Builder() {}
 
       /**
-       * Sets the duration of the animation in milliseconds. If not set, defaults to 300ms.
+       * Sets animation parameters including duration, easing and repeat delay.
        *
        * @since 1.2
        */
       @NonNull
-      public Builder setDurationMillis(int durationMillis) {
-        mImpl.setDurationMillis(durationMillis);
-        mFingerprint.recordPropertyUpdate(1, durationMillis);
-        return this;
-      }
-
-      /**
-       * Sets the delay to start the animation in milliseconds. If not set, defaults to 0.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setStartDelayMillis(int startDelayMillis) {
-        mImpl.setStartDelayMillis(startDelayMillis);
-        mFingerprint.recordPropertyUpdate(2, startDelayMillis);
-        return this;
-      }
-
-      /**
-       * Sets the easing to be used for adjusting an animation's fraction. If not set, defaults to
-       * Linear Interpolator.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setEasing(@NonNull Easing easing) {
-        mImpl.setEasing(easing.toEasingProto());
+      public Builder setAnimationParameters(@NonNull AnimationParameters animationParameters) {
+        mImpl.setAnimationParameters(animationParameters.toProto());
         mFingerprint.recordPropertyUpdate(
-            3, checkNotNull(easing.getFingerprint()).aggregateValueAsInt());
+            4, checkNotNull(animationParameters.getFingerprint()).aggregateValueAsInt());
         return this;
       }
 
@@ -304,6 +257,153 @@
   }
 
   /**
+   * Animation specs of duration, easing and repeat delay.
+   *
+   * @since 1.2
+   */
+  public static final class AnimationParameters {
+    private final AnimationParameterProto.AnimationParameters mImpl;
+    @Nullable private final Fingerprint mFingerprint;
+
+    AnimationParameters(
+        AnimationParameterProto.AnimationParameters impl, @Nullable Fingerprint fingerprint) {
+      this.mImpl = impl;
+      this.mFingerprint = fingerprint;
+    }
+
+    /**
+     * Gets the duration of the animation in milliseconds.
+     *
+     * @since 1.2
+     */
+    public int getDurationMillis() {
+      return mImpl.getDurationMillis();
+    }
+
+    /**
+     * Gets the easing to be used for adjusting an animation's fraction.
+     *
+     * @since 1.2
+     */
+    @Nullable
+    public Easing getEasing() {
+      if (mImpl.hasEasing()) {
+        return AnimationParameterBuilders.easingFromProto(mImpl.getEasing());
+      } else {
+        return null;
+      }
+    }
+
+    /**
+     * Gets animation delay in millis. When used outside repeatable, this is the delay to start the
+     * animation in milliseconds. When set inside repeatable, this is the delay before repeating
+     * animation in milliseconds.
+     *
+     * @since 1.2
+     */
+    public int getDelayMillis() {
+      return mImpl.getDelayMillis();
+    }
+
+    /** Get the fingerprint for this object, or null if unknown. */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @Nullable
+    public Fingerprint getFingerprint() {
+      return mFingerprint;
+    }
+
+    /** Creates a new wrapper instance from the proto. */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static AnimationParameters fromProto(
+        @NonNull AnimationParameterProto.AnimationParameters proto,
+        @Nullable Fingerprint fingerprint) {
+      return new AnimationParameters(proto, fingerprint);
+    }
+
+    @NonNull
+    static AnimationParameters fromProto(
+        @NonNull AnimationParameterProto.AnimationParameters proto) {
+      return fromProto(proto, null);
+    }
+
+    /** Returns the internal proto instance. */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public AnimationParameterProto.AnimationParameters toProto() {
+      return mImpl;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+      return "AnimationParameters{"
+          + "durationMillis="
+          + getDurationMillis()
+          + ", easing="
+          + getEasing()
+          + ", delayMillis="
+          + getDelayMillis()
+          + "}";
+    }
+
+    /** Builder for {@link AnimationParameters} */
+    public static final class Builder {
+      private final AnimationParameterProto.AnimationParameters.Builder mImpl =
+          AnimationParameterProto.AnimationParameters.newBuilder();
+      private final Fingerprint mFingerprint = new Fingerprint(-1301308590);
+
+      public Builder() {}
+
+      /**
+       * Sets the duration of the animation in milliseconds. If not set, defaults to 300ms.
+       *
+       * @since 1.2
+       */
+      @NonNull
+      public Builder setDurationMillis(int durationMillis) {
+        mImpl.setDurationMillis(durationMillis);
+        mFingerprint.recordPropertyUpdate(1, durationMillis);
+        return this;
+      }
+
+      /**
+       * Sets the easing to be used for adjusting an animation's fraction. If not set, defaults to
+       * Linear Interpolator.
+       *
+       * @since 1.2
+       */
+      @NonNull
+      public Builder setEasing(@NonNull Easing easing) {
+        mImpl.setEasing(easing.toEasingProto());
+        mFingerprint.recordPropertyUpdate(
+            2, checkNotNull(easing.getFingerprint()).aggregateValueAsInt());
+        return this;
+      }
+
+      /**
+       * Sets animation delay in millis. When used outside repeatable, this is the delay to start
+       * the animation in milliseconds. When set inside repeatable, this is the delay before
+       * repeating animation in milliseconds. If not set, no delay will be applied.
+       *
+       * @since 1.2
+       */
+      @NonNull
+      public Builder setDelayMillis(int delayMillis) {
+        mImpl.setDelayMillis(delayMillis);
+        mFingerprint.recordPropertyUpdate(3, delayMillis);
+        return this;
+      }
+
+      /** Builds an instance from accumulated values. */
+      @NonNull
+      public AnimationParameters build() {
+        return new AnimationParameters(mImpl.build(), mFingerprint);
+      }
+    }
+  }
+
+  /**
    * Interface defining the easing to be used for adjusting an animation's fraction. This allows
    * animation to speed up and slow down, rather than moving at a constant rate. If not set,
    * defaults to Linear Interpolator.
@@ -599,27 +699,34 @@
     }
 
     /**
-     * Gets the delay before the forward part of the repeat in milliseconds.
+     * Gets optional custom parameters for the forward passes of animation.
      *
      * @since 1.2
      */
-    public int getForwardRepeatDelayMillis() {
-      return mImpl.getForwardRepeatDelayMillis();
+    @Nullable
+    public AnimationParameters getForwardRepeatOverride() {
+      if (mImpl.hasForwardRepeatOverride()) {
+        return AnimationParameters.fromProto(mImpl.getForwardRepeatOverride());
+      } else {
+        return null;
+      }
     }
 
     /**
-     * Gets the delay before the reverse part of repeat in milliseconds.
+     * Gets optional custom parameters for the reverse passes of animation.
      *
      * @since 1.2
      */
-    public int getReverseRepeatDelayMillis() {
-      return mImpl.getReverseRepeatDelayMillis();
+    @Nullable
+    public AnimationParameters getReverseRepeatOverride() {
+      if (mImpl.hasReverseRepeatOverride()) {
+        return AnimationParameters.fromProto(mImpl.getReverseRepeatOverride());
+      } else {
+        return null;
+      }
     }
 
-    /**
-     * Get the fingerprint for this object, or null if unknown.
-     *
-     */
+    /** Get the fingerprint for this object, or null if unknown. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
     public Fingerprint getFingerprint() {
@@ -664,10 +771,10 @@
           + getIterations()
           + ", repeatMode="
           + getRepeatMode()
-          + ", forwardRepeatDelayMillis="
-          + getForwardRepeatDelayMillis()
-          + ", reverseRepeatDelayMillis="
-          + getReverseRepeatDelayMillis()
+          + ", forwardRepeatOverride="
+          + getForwardRepeatOverride()
+          + ", reverseRepeatOverride="
+          + getReverseRepeatOverride()
           + "}";
     }
 
@@ -706,28 +813,32 @@
       }
 
       /**
-       * Sets the delay before the forward part of the repeat in milliseconds. If not set,
-       * defaults to 0.
+       * Sets optional custom parameters for the forward passes of animation. If not set, use the
+       * main animation parameters set outside of {@link Repeatable}.
        *
        * @since 1.2
        */
       @NonNull
-      public Builder setForwardRepeatDelayMillis(int forwardRepeatDelayMillis) {
-        mImpl.setForwardRepeatDelayMillis(forwardRepeatDelayMillis);
-        mFingerprint.recordPropertyUpdate(3, forwardRepeatDelayMillis);
+      public Builder setForwardRepeatOverride(
+          @NonNull AnimationParameters forwardRepeatOverride) {
+        mImpl.setForwardRepeatOverride(forwardRepeatOverride.toProto());
+        mFingerprint.recordPropertyUpdate(
+            6, checkNotNull(forwardRepeatOverride.getFingerprint()).aggregateValueAsInt());
         return this;
       }
 
       /**
-       * Sets the delay before the reverse part of the repeat in milliseconds. This delay will
-       * not be used when the repeat mode is restart. If not set, defaults to 0.
+       * Sets optional custom parameters for the reverse passes of animation. If not set, use the
+       * main animation parameters set outside of {@link Repeatable}.
        *
        * @since 1.2
        */
       @NonNull
-      public Builder setReverseRepeatDelayMillis(int reverseRepeatDelayMillis) {
-        mImpl.setReverseRepeatDelayMillis(reverseRepeatDelayMillis);
-        mFingerprint.recordPropertyUpdate(4, reverseRepeatDelayMillis);
+      public Builder setReverseRepeatOverride(
+          @NonNull AnimationParameters reverseRepeatOverride) {
+        mImpl.setReverseRepeatOverride(reverseRepeatOverride.toProto());
+        mFingerprint.recordPropertyUpdate(
+            7, checkNotNull(reverseRepeatOverride.getFingerprint()).aggregateValueAsInt());
         return this;
       }
 
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
index 299d7b9..05d9c21 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
@@ -150,7 +150,10 @@
     static final int ARITHMETIC_OP_TYPE_MODULO = 5;
 
     /**
-     * Rounding mode to use when converting a float to an int32.
+     * Rounding mode to use when converting a float to an int32. If the value is larger than {@link
+     * Integer#MAX_VALUE} or smaller than {@link Integer#MIN_VALUE}, the result of this operation
+     * will be invalid and will have an invalid value delivered via
+     * {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
      *
      * @since 1.2
      */
@@ -2219,8 +2222,8 @@
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicInt32} (with default formatting parameters). As an example, in the English locale,
-         * the following is equal to {@code DynamicString.constant("12")}
+         * DynamicInt32} (with default formatting parameters). As an example, for locale en_US, the
+         * following is equal to {@code DynamicString.constant("12")}
          *
          * <pre>
          *   DynamicInt32.constant(12).format()
@@ -2230,65 +2233,115 @@
          */
         @NonNull
         default DynamicString format() {
-            return IntFormatter.with().buildForInput(this);
+            return new IntFormatter.Builder().build().getInt32FormatOp(this);
         }
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicInt32}. As an example, in the English locale, the following is equal to {@code
+         * DynamicInt32}. As an example, for locale en_US, the following is equal to {@code
          * DynamicString.constant("0,012")}
          *
          * <pre>
          *   DynamicInt32.constant(12)
          *            .format(
-         *                IntFormatter.with().minIntegerDigits(4).groupingUsed(true));
+         *                new IntFormatter.Builder()
+         *                                .setMinIntegerDigits(4)
+         *                                .setGroupingUsed(true)
+         *                                .build());
          * </pre>
          *
-         * The resulted {@link DynamicString} is subject to being truncated if it's too long.
-         *
          * @param formatter The formatting parameter.
          */
         @NonNull
         default DynamicString format(@NonNull IntFormatter formatter) {
-            return formatter.buildForInput(this);
+            return formatter.getInt32FormatOp(this);
         }
 
         /** Allows formatting {@link DynamicInt32} into a {@link DynamicString}. */
         class IntFormatter {
-            private final Int32FormatOp.Builder builder;
+            private final Int32FormatOp.Builder mInt32FormatOpBuilder;
+            private final Int32FormatOp mInt32FormatOp;
 
-            private IntFormatter() {
-                builder = new Int32FormatOp.Builder();
-            }
-
-            /** Creates an instance of {@link IntFormatter} with default configuration. */
-            @NonNull
-            public static IntFormatter with() {
-                return new IntFormatter();
-            }
-
-            /**
-             * Sets minimum number of integer digits for the formatter. Defaults to one if not
-             * specified.
-             */
-            @NonNull
-            public IntFormatter minIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
-                builder.setMinIntegerDigits(minIntegerDigits);
-                return this;
-            }
-
-            /**
-             * Sets whether grouping is used for the formatter. Defaults to false if not specified.
-             */
-            @NonNull
-            public IntFormatter groupingUsed(boolean groupingUsed) {
-                builder.setGroupingUsed(groupingUsed);
-                return this;
+            IntFormatter(@NonNull Int32FormatOp.Builder int32FormatOpBuilder) {
+                mInt32FormatOpBuilder = int32FormatOpBuilder;
+                mInt32FormatOp = int32FormatOpBuilder.build();
             }
 
             @NonNull
-            Int32FormatOp buildForInput(@NonNull DynamicInt32 dynamicInt32) {
-                return builder.setInput(dynamicInt32).build();
+            Int32FormatOp getInt32FormatOp(@NonNull DynamicInt32 dynamicInt32) {
+                return mInt32FormatOpBuilder.setInput(dynamicInt32).build();
+            }
+
+            /** Returns the minimum number of digits allowed in the integer portion of a number. */
+            @IntRange(from = 0)
+            public int getMinIntegerDigits() {
+                return mInt32FormatOp.getMinIntegerDigits();
+            }
+
+            /** Returns whether digit grouping is used or not. */
+            public boolean isGroupingUsed() {
+                return mInt32FormatOp.getGroupingUsed();
+            }
+
+            /** Builder to create {@link IntFormatter} objects. */
+            public static final class Builder {
+                private static final int MAX_INTEGER_PART_LENGTH = 15;
+                final Int32FormatOp.Builder mBuilder;
+
+                public Builder() {
+                    mBuilder = new Int32FormatOp.Builder();
+                }
+
+                /**
+                 * Sets minimum number of integer digits for the formatter. Defaults to one if not
+                 * specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
+                 * part will not appear.
+                 */
+                @NonNull
+                public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
+                    mBuilder.setMinIntegerDigits(minIntegerDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets whether grouping is used for the formatter. Defaults to false if not
+                 * specified. If grouping is used, digits will be grouped into digit groups using a
+                 * separator. Digit group size and used separator can vary in different
+                 * countries/regions. As an example, for locale en_US, the following is equal to
+                 * {@code * DynamicString.constant("1,234")}
+                 *
+                 * <pre>
+                 *   DynamicInt32.constant(1234)
+                 *       .format(
+                 *           new IntFormatter.Builder()
+                 *                           .setGroupingUsed(true).build());
+                 * </pre>
+                 */
+                @NonNull
+                public Builder setGroupingUsed(boolean groupingUsed) {
+                    mBuilder.setGroupingUsed(groupingUsed);
+                    return this;
+                }
+
+                /** Builds an instance with values accumulated in this Builder. */
+                @NonNull
+                public IntFormatter build() {
+                    throwIfExceedingMaxValue(
+                            "MinIntegerDigits",
+                            mBuilder.build().getMinIntegerDigits(),
+                            MAX_INTEGER_PART_LENGTH);
+                    return new IntFormatter(mBuilder);
+                }
+
+                private static void throwIfExceedingMaxValue(
+                        String paramName, int value, int maxValue) {
+                    if (value > maxValue) {
+                        throw new IllegalArgumentException(
+                                String.format(
+                                        "%s (%d) is too large. Maximum value for %s is %d",
+                                        paramName, value, paramName, maxValue));
+                    }
+                }
             }
         }
 
@@ -2374,8 +2427,8 @@
 
         /**
          * Gets minimum integer digits. Sign and grouping characters are not considered when
-         * applying minIntegerDigits constraint. If not defined, defaults to one. For example,in the
-         * English locale, applying minIntegerDigit=4 to 12 would yield "0012".
+         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
+         * locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
          *
          * @since 1.2
          */
@@ -2386,8 +2439,8 @@
 
         /**
          * Gets digit grouping used. Grouping size and grouping character depend on the current
-         * locale. If not defined, defaults to false. For example, in the English locale, using
-         * grouping with 1234 would yield "1,234".
+         * locale. If not defined, defaults to false. For example, for locale en_US, using grouping
+         * with 1234 would yield "1,234".
          *
          * @since 1.2
          */
@@ -2434,7 +2487,7 @@
 
         /** Builder for {@link Int32FormatOp}. */
         public static final class Builder implements DynamicString.Builder {
-            private final DynamicProto.Int32FormatOp.Builder mImpl =
+            final DynamicProto.Int32FormatOp.Builder mImpl =
                     DynamicProto.Int32FormatOp.newBuilder();
             private final Fingerprint mFingerprint = new Fingerprint(196209833);
 
@@ -2455,8 +2508,8 @@
 
             /**
              * Sets minimum integer digits. Sign and grouping characters are not considered when
-             * applying minIntegerDigits constraint. If not defined, defaults to one. For example,in
-             * the English locale, applying minIntegerDigit=4 to 12 would yield "0012".
+             * applying minIntegerDigits constraint. If not defined, defaults to one. For example,
+             * for locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
              *
              * @since 1.2
              */
@@ -2469,7 +2522,7 @@
 
             /**
              * Sets digit grouping used. Grouping size and grouping character depend on the current
-             * locale. If not defined, defaults to false. For example, in the English locale, using
+             * locale. If not defined, defaults to false. For example, for locale en_US, using
              * grouping with 1234 would yield "1,234".
              *
              * @since 1.2
@@ -2898,8 +2951,8 @@
 
         /**
          * Gets minimum integer digits. Sign and grouping characters are not considered when
-         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, in
-         * the English locale, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
+         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
+         * locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
          *
          * @since 1.2
          */
@@ -2910,8 +2963,8 @@
 
         /**
          * Gets digit grouping used. Grouping size and grouping character depend on the current
-         * locale. If not defined, defaults to false. For example, in the English locale, using
-         * grouping with 1234.56 would yield "1,234.56".
+         * locale. If not defined, defaults to false. For example, for locale en_US, using grouping
+         * with 1234.56 would yield "1,234.56".
          *
          * @since 1.2
          */
@@ -3014,7 +3067,7 @@
             /**
              * Sets minimum integer digits. Sign and grouping characters are not considered when
              * applying minIntegerDigits constraint. If not defined, defaults to one. For example,
-             * in the English locale, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
+             * for locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
              *
              * @since 1.2
              */
@@ -3027,7 +3080,7 @@
 
             /**
              * Sets digit grouping used. Grouping size and grouping character depend on the current
-             * locale. If not defined, defaults to false. For example, in the English locale, using
+             * locale. If not defined, defaults to false. For example, for locale en_US, using
              * grouping with 1234.56 would yield "1,234.56".
              *
              * @since 1.2
@@ -3051,7 +3104,7 @@
     /**
      * Interface defining a dynamic string type.
      *
-     * <p> {@link DynamicString} string value is subject to being truncated if it's too long.
+     * <p>{@link DynamicString} string value is subject to being truncated if it's too long.
      *
      * @since 1.2
      */
@@ -3802,7 +3855,13 @@
             return toDynamicFloatProto().toByteArray();
         }
 
-        /** Creates a constant-valued {@link DynamicFloat}. */
+        /**
+         * Creates a constant-valued {@link DynamicFloat}.
+         *
+         * <p>If {@code Float.isNan(constant)} is true, the value will be invalid. And any
+         * expression that uses this {@link DynamicFloat} will have an invalid result (which will be
+         * delivered through {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
+         */
         @NonNull
         static DynamicFloat constant(float constant) {
             return new FixedFloat.Builder().setValue(constant).build();
@@ -3907,6 +3966,11 @@
         /**
          * Returns a {@link DynamicInt32} which holds the largest integer value that is smaller than
          * or equal to this {@link DynamicFloat}, i.e. {@code int result = (int) Math.floor(this)}
+         *
+         * <p>If the float value is larger than {@link Integer#MAX_VALUE} or smaller than {@link
+         * Integer#MIN_VALUE}, the result of this operation will be invalid and any expression that
+         * uses the {@link DynamicInt32} will have an invalid result (which will be delivered
+         * through {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
          */
         @NonNull
         default DynamicInt32 asInt() {
@@ -4467,8 +4531,8 @@
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicFloat} (with default formatting parameters). As an example, in the English locale,
-         * the following is equal to {@code DynamicString.constant("12.346")}
+         * DynamicFloat} (with default formatting parameters). As an example, for locale en_US, the
+         * following is equal to {@code DynamicString.constant("12.346")}
          *
          * <pre>
          *   DynamicFloat.constant(12.34567f).format();
@@ -4478,19 +4542,19 @@
          */
         @NonNull
         default DynamicString format() {
-            return FloatFormatter.with().buildForInput(this);
+            return new FloatFormatter.Builder().build().getFloatFormatOp(this);
         }
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicFloat}. As an example, in the English locale, the following is equal to {@code
+         * DynamicFloat}. As an example, for locale en_US, the following is equal to {@code
          * DynamicString.constant("0,012.34")}
          *
          * <pre>
          *   DynamicFloat.constant(12.345f)
          *       .format(
-         *           FloatFormatter.with().maxFractionDigits(2).minIntegerDigits(4)
-         *                         .groupingUsed(true));
+         *           new FloatFormatter.Builder().setMaxFractionDigits(2).setMinIntegerDigits(4)
+         *                             .setGroupingUsed(true).build());
          * </pre>
          *
          * The resulted {@link DynamicString} is subject to being truncated if it's too long.
@@ -4499,67 +4563,138 @@
          */
         @NonNull
         default DynamicString format(@NonNull FloatFormatter formatter) {
-            return formatter.buildForInput(this);
+            return formatter.getFloatFormatOp(this);
         }
 
         /** Allows formatting {@link DynamicFloat} into a {@link DynamicString}. */
         class FloatFormatter {
-            private final FloatFormatOp.Builder builder;
+            private final FloatFormatOp.Builder mFloatFormatOpBuilder;
+            private final FloatFormatOp mFloatFormatOp;
 
-            private FloatFormatter() {
-                builder = new FloatFormatOp.Builder();
-            }
-
-            /** Creates an instance of {@link FloatFormatter} with default configuration. */
-            @NonNull
-            public static FloatFormatter with() {
-                return new FloatFormatter();
-            }
-
-            /**
-             * Sets minimum number of fraction digits for the formatter. Defaults to zero if not
-             * specified. minimumFractionDigits must be <= maximumFractionDigits. If the condition
-             * is not satisfied, then minimumFractionDigits will be used for both fields.
-             */
-            @NonNull
-            public FloatFormatter minFractionDigits(@IntRange(from = 0) int minFractionDigits) {
-                builder.setMinFractionDigits(minFractionDigits);
-                return this;
-            }
-
-            /**
-             * Sets maximum number of fraction digits for the formatter. Defaults to three if not
-             * specified. minimumFractionDigits must be <= maximumFractionDigits. If the condition
-             * is not satisfied, then minimumFractionDigits will be used for both fields.
-             */
-            @NonNull
-            public FloatFormatter maxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
-                builder.setMaxFractionDigits(maxFractionDigits);
-                return this;
-            }
-
-            /**
-             * Sets minimum number of integer digits for the formatter. Defaults to one if not
-             * specified.
-             */
-            @NonNull
-            public FloatFormatter minIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
-                builder.setMinIntegerDigits(minIntegerDigits);
-                return this;
-            }
-
-            /**
-             * Sets whether grouping is used for the formatter. Defaults to false if not specified.
-             */
-            @NonNull
-            public FloatFormatter groupingUsed(boolean groupingUsed) {
-                builder.setGroupingUsed(groupingUsed);
-                return this;
+            FloatFormatter(FloatFormatOp.Builder floatFormatOpBuilder) {
+                mFloatFormatOpBuilder = floatFormatOpBuilder;
+                mFloatFormatOp = floatFormatOpBuilder.build();
             }
 
             @NonNull
-            FloatFormatOp buildForInput(@NonNull DynamicFloat dynamicFloat) {
-                return builder.setInput(dynamicFloat).build();
+            FloatFormatOp getFloatFormatOp(@NonNull DynamicFloat dynamicFloat) {
+                return mFloatFormatOpBuilder.setInput(dynamicFloat).build();
+            }
+
+            /** Returns the minimum number of digits allowed in the fraction portion of a number. */
+            @IntRange(from = 0)
+            public int getMinFractionDigits() {
+                return mFloatFormatOp.getMinFractionDigits();
+            }
+
+            /** Returns the maximum number of digits allowed in the fraction portion of a number. */
+            @IntRange(from = 0)
+            public int getMaxFractionDigits() {
+                return mFloatFormatOp.getMaxFractionDigits();
+            }
+
+            /** Returns the minimum number of digits allowed in the integer portion of a number. */
+            @IntRange(from = 0)
+            public int getMinIntegerDigits() {
+                return mFloatFormatOp.getMinIntegerDigits();
+            }
+
+            /** Returns whether digit grouping is used or not. */
+            public boolean isGroupingUsed() {
+                return mFloatFormatOp.getGroupingUsed();
+            }
+
+            /** Builder to create {@link FloatFormatter} objects. */
+            public static final class Builder {
+                private static final int MAX_INTEGER_PART_LENGTH = 15;
+                private static final int MAX_FRACTION_PART_LENGTH = 15;
+                final FloatFormatOp.Builder mBuilder;
+
+                public Builder() {
+                    mBuilder = new FloatFormatOp.Builder();
+                }
+
+                /**
+                 * Sets minimum number of fraction digits for the formatter. Defaults to zero if not
+                 * specified. minimumFractionDigits must be <= maximumFractionDigits. If the
+                 * condition is not satisfied, then minimumFractionDigits will be used for both
+                 * fields.
+                 */
+                @NonNull
+                public Builder setMinFractionDigits(@IntRange(from = 0) int minFractionDigits) {
+                    mBuilder.setMinFractionDigits(minFractionDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets maximum number of fraction digits for the formatter. Defaults to three if
+                 * not specified. minimumFractionDigits must be <= maximumFractionDigits. If the
+                 * condition is not satisfied, then minimumFractionDigits will be used for both
+                 * fields.
+                 */
+                @NonNull
+                public Builder setMaxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
+                    mBuilder.setMaxFractionDigits(maxFractionDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets minimum number of integer digits for the formatter. Defaults to one if not
+                 * specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
+                 * part will not appear.
+                 */
+                @NonNull
+                public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
+                    mBuilder.setMinIntegerDigits(minIntegerDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets whether grouping is used for the formatter. Defaults to false if not
+                 * specified. If grouping is used, digits will be grouped into digit groups using a
+                 * separator. Digit group size and used separator can vary in different
+                 * countries/regions. As an example, for locale en_US, the following is equal to
+                 * {@code * DynamicString.constant("1,234")}
+                 *
+                 * <pre>
+                 *   DynamicFloat.constant(1234)
+                 *       .format(
+                 *           new FloatFormatter.Builder()
+                 *                           .setGroupingUsed(true).build());
+                 * </pre>
+                 */
+                @NonNull
+                public Builder setGroupingUsed(boolean groupingUsed) {
+                    mBuilder.setGroupingUsed(groupingUsed);
+                    return this;
+                }
+
+                /** Builds an instance with values accumulated in this Builder. */
+                @NonNull
+                public FloatFormatter build() {
+                    FloatFormatOp op = mBuilder.build();
+                    throwIfExceedingMaxValue(
+                            "MinFractionDigits",
+                            op.getMinFractionDigits(),
+                            MAX_FRACTION_PART_LENGTH);
+                    throwIfExceedingMaxValue(
+                            "MaxFractionDigits",
+                            op.getMaxFractionDigits(),
+                            MAX_FRACTION_PART_LENGTH);
+                    throwIfExceedingMaxValue(
+                            "MinIntegerDigits", op.getMinIntegerDigits(), MAX_INTEGER_PART_LENGTH);
+                    return new FloatFormatter(mBuilder);
+                }
+
+                private static void throwIfExceedingMaxValue(
+                        String paramName, int value, int maxValue) {
+                    if (value > maxValue) {
+                        throw new IllegalArgumentException(
+                                String.format(
+                                        "%s (%d) is too large. Maximum value for %s is %d",
+                                        paramName, value, paramName, maxValue));
+                    }
+                }
             }
         }
 
@@ -5245,18 +5380,12 @@
             return new StateBoolSource.Builder().setSourceKey(stateKey).build();
         }
 
-        /** Returns a {@link DynamicBool} that has the same value as this {@link DynamicBool}. */
-        @NonNull
-        default DynamicBool isTrue() {
-            return this;
-        }
-
         /**
          * Returns a {@link DynamicBool} that has the opposite value of this {@link DynamicBool}.
          * i.e. {code result = !this}
          */
         @NonNull
-        default DynamicBool isFalse() {
+        default DynamicBool negate() {
             return new NotBoolOp.Builder().setInput(this).build();
         }
 
@@ -5682,6 +5811,170 @@
     }
 
     /**
+     * A conditional operator which yields a color depending on the boolean operand. This
+     * implements:
+     *
+     * <pre>{@code
+     * color result = condition ? value_if_true : value_if_false
+     * }</pre>
+     *
+     * @since 1.2
+     */
+    static final class ConditionalColorOp implements DynamicColor {
+        private final DynamicProto.ConditionalColorOp mImpl;
+        @Nullable private final Fingerprint mFingerprint;
+
+        ConditionalColorOp(
+                DynamicProto.ConditionalColorOp impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
+
+        /**
+         * Gets the condition to use.
+         *
+         * @since 1.2
+         */
+        @Nullable
+        public DynamicBool getCondition() {
+            if (mImpl.hasCondition()) {
+                return DynamicBuilders.dynamicBoolFromProto(mImpl.getCondition());
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gets the color to yield if condition is true.
+         *
+         * @since 1.2
+         */
+        @Nullable
+        public DynamicColor getValueIfTrue() {
+            if (mImpl.hasValueIfTrue()) {
+                return DynamicBuilders.dynamicColorFromProto(mImpl.getValueIfTrue());
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gets the color to yield if condition is false.
+         *
+         * @since 1.2
+         */
+        @Nullable
+        public DynamicColor getValueIfFalse() {
+            if (mImpl.hasValueIfFalse()) {
+                return DynamicBuilders.dynamicColorFromProto(mImpl.getValueIfFalse());
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
+
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static ConditionalColorOp fromProto(
+                @NonNull DynamicProto.ConditionalColorOp proto, @Nullable Fingerprint fingerprint) {
+            return new ConditionalColorOp(proto, fingerprint);
+        }
+
+        @NonNull
+        static ConditionalColorOp fromProto(@NonNull DynamicProto.ConditionalColorOp proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        DynamicProto.ConditionalColorOp toProto() {
+            return mImpl;
+        }
+
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicColor toDynamicColorProto() {
+            return DynamicProto.DynamicColor.newBuilder().setConditionalOp(mImpl).build();
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "ConditionalColorOp{"
+                    + "condition="
+                    + getCondition()
+                    + ", valueIfTrue="
+                    + getValueIfTrue()
+                    + ", valueIfFalse="
+                    + getValueIfFalse()
+                    + "}";
+        }
+
+        /** Builder for {@link ConditionalColorOp}. */
+        public static final class Builder implements DynamicColor.Builder {
+            private final DynamicProto.ConditionalColorOp.Builder mImpl =
+                    DynamicProto.ConditionalColorOp.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-1961850082);
+
+            public Builder() {}
+
+            /**
+             * Sets the condition to use.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setCondition(@NonNull DynamicBool condition) {
+                mImpl.setCondition(condition.toDynamicBoolProto());
+                mFingerprint.recordPropertyUpdate(
+                        1, checkNotNull(condition.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            /**
+             * Sets the color to yield if condition is true.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setValueIfTrue(@NonNull DynamicColor valueIfTrue) {
+                mImpl.setValueIfTrue(valueIfTrue.toDynamicColorProto());
+                mFingerprint.recordPropertyUpdate(
+                        2, checkNotNull(valueIfTrue.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            /**
+             * Sets the color to yield if condition is false.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setValueIfFalse(@NonNull DynamicColor valueIfFalse) {
+                mImpl.setValueIfFalse(valueIfFalse.toDynamicColorProto());
+                mFingerprint.recordPropertyUpdate(
+                        3, checkNotNull(valueIfFalse.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            @Override
+            @NonNull
+            public ConditionalColorOp build() {
+                return new ConditionalColorOp(mImpl.build(), mFingerprint);
+            }
+        }
+    }
+
+    /**
      * Interface defining a dynamic color type.
      *
      * @since 1.2
@@ -5817,6 +6110,24 @@
             return new AnimatableDynamicColor.Builder().setInput(this).build();
         }
 
+        /**
+         * Bind the value of this {@link DynamicColor} to the result of a conditional expression.
+         * This will use the value given in either {@link ConditionScope#use} or {@link
+         * ConditionScopes.IfTrueScope#elseUse} depending on the value yielded from {@code
+         * condition}.
+         */
+        @NonNull
+        static ConditionScope<DynamicColor, Integer> onCondition(@NonNull DynamicBool condition) {
+            return new ConditionScopes.ConditionScope<>(
+                    (trueValue, falseValue) ->
+                            new ConditionalColorOp.Builder()
+                                    .setCondition(condition)
+                                    .setValueIfTrue(trueValue)
+                                    .setValueIfFalse(falseValue)
+                                    .build(),
+                    DynamicColor::constant);
+        }
+
         /** Get the fingerprint for this object or null if unknown. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Nullable
@@ -5851,6 +6162,9 @@
         if (proto.hasAnimatableDynamic()) {
             return AnimatableDynamicColor.fromProto(proto.getAnimatableDynamic());
         }
+        if (proto.hasConditionalOp()) {
+            return ConditionalColorOp.fromProto(proto.getConditionalOp());
+        }
         throw new IllegalStateException("Proto was not a recognised instance of DynamicColor");
     }
 
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
index 8809e61..f9829cd 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
@@ -230,7 +230,8 @@
     }
 
     /**
-     * Gets the value.
+     * Gets the value. Note that a NaN value is considered invalid and any expression with this node
+     * will have an invalid value delivered via {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
      *
      * @since 1.2
      */
@@ -284,8 +285,11 @@
 
       public Builder() {}
 
+
       /**
-       * Sets the value.
+       * Sets the value. Note that a NaN value is considered invalid and any expression with this
+       * node will have an invalid value delivered via
+       * {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
        *
        * @since 1.2
        */
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/AnimationSpecTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/AnimationSpecTest.java
index cc15685..442821b 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/AnimationSpecTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/AnimationSpecTest.java
@@ -17,59 +17,113 @@
 package androidx.wear.protolayout.expression;
 
 import static androidx.wear.protolayout.expression.AnimationParameterBuilders.REPEAT_MODE_RESTART;
-import static androidx.wear.protolayout.expression.AnimationParameterBuilders.REPEAT_MODE_REVERSE;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.CubicBezierEasing;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class AnimationSpecTest {
-  @Test
-  public void animationSpecToString() {
-    assertThat(
-            new AnimationSpec.Builder()
-                .setDurationMillis(1)
-                .setStartDelayMillis(2)
-                .setEasing(new CubicBezierEasing.Builder().setX1(3f).build())
-                .setRepeatable(new Repeatable.Builder().setIterations(4).build())
-                .build()
-                .toString())
-        .isEqualTo(
-            "AnimationSpec{durationMillis=1, startDelayMillis=2, "
-                + "easing=CubicBezierEasing{x1=3.0, y1=0.0, x2=0.0, y2=0.0}, "
-                + "repeatable=Repeatable{iterations=4, repeatMode=0, "
-                + "forwardRepeatDelayMillis=0, reverseRepeatDelayMillis=0}}");
-  }
+    @Test
+    public void animationSpecToString_deprecated() {
+        assertThat(
+                new AnimationSpec.Builder()
 
-  @Test
-  public void cubicBezierEasingToString() {
-    assertThat(
-            new CubicBezierEasing.Builder()
-                .setX1(1f)
-                .setY1(2f)
-                .setX2(3f)
-                .setY2(4f)
-                .build()
-                .toString())
-        .isEqualTo("CubicBezierEasing{x1=1.0, y1=2.0, x2=3.0, y2=4.0}");
-  }
+                        .setAnimationParameters(
+                                new AnimationParameters.Builder()
+                                        .setDurationMillis(1)
+                                        .setDelayMillis(2)
+                                        .setEasing(
+                                                new CubicBezierEasing.Builder().setX1(3f).build())
+                                        .build())
+                        .setRepeatable(new Repeatable.Builder().setIterations(4).build())
+                        .build()
+                        .toString())
+                .isEqualTo(
+                        "AnimationSpec{animationParameters=AnimationParameters{durationMillis=1, "
+                                + "easing=CubicBezierEasing{x1=3.0, y1=0.0, x2=0.0, y2=0.0}, "
+                                + "delayMillis=2}, "
+                                + "repeatable=Repeatable{iterations=4, repeatMode=0, "
+                                + "forwardRepeatOverride=null, "
+                                + "reverseRepeatOverride=null}}");
+    }
 
-  @Test
-  public void repeatableToString() {
-    assertThat(
-            new Repeatable.Builder()
-                .setIterations(10)
-                .setRepeatMode(REPEAT_MODE_RESTART)
-                .setForwardRepeatDelayMillis(200)
-                .setReverseRepeatDelayMillis(100)
-                .build()
-                .toString())
-        .isEqualTo("Repeatable{iterations=10, repeatMode=1, "
-                + "forwardRepeatDelayMillis=200, reverseRepeatDelayMillis=100}");
-  }
+    @Test
+    public void animationSpecToString() {
+        assertThat(
+                new AnimationSpec.Builder()
+                        .setAnimationParameters(
+                                new AnimationParameters.Builder()
+                                        .setDurationMillis(20)
+                                        .setEasing(
+                                                new CubicBezierEasing.Builder().setX1(3f).build())
+                                        .setDelayMillis(10)
+                                        .build())
+                        .setRepeatable(new Repeatable.Builder().setIterations(4).build())
+                        .build()
+                        .toString())
+                .isEqualTo(
+                        "AnimationSpec{animationParameters=AnimationParameters{durationMillis=20,"
+                                + " easing=CubicBezierEasing{x1=3.0, y1=0.0, x2=0.0, y2=0.0},"
+                                + " delayMillis=10}, repeatable=Repeatable{iterations=4,"
+                                + " repeatMode=0, forwardRepeatOverride=null, "
+                                + "reverseRepeatOverride=null}}");
+    }
+
+    @Test
+    public void cubicBezierEasingToString() {
+        assertThat(
+                new CubicBezierEasing.Builder()
+                        .setX1(1f)
+                        .setY1(2f)
+                        .setX2(3f)
+                        .setY2(4f)
+                        .build()
+                        .toString())
+                .isEqualTo("CubicBezierEasing{x1=1.0, y1=2.0, x2=3.0, y2=4.0}");
+    }
+
+    @Test
+    public void repeatableToString() {
+        assertThat(
+                new Repeatable.Builder()
+                        .setIterations(10)
+                        .setRepeatMode(REPEAT_MODE_RESTART)
+                        .setReverseRepeatOverride(
+                                new AnimationParameters.Builder()
+                                        .setDurationMillis(20)
+                                        .setEasing(
+                                                new CubicBezierEasing.Builder().setX1(3f).build())
+                                        .setDelayMillis(10)
+                                        .build())
+                        .build()
+                        .toString())
+                .isEqualTo(
+                        "Repeatable{iterations=10, repeatMode=1, forwardRepeatOverride=null,"
+                                + " reverseRepeatOverride=AnimationParameters{durationMillis"
+                                + "=20,"
+                                + " easing=CubicBezierEasing{x1=3.0, y1=0.0, x2=0.0, y2=0.0}, "
+                                + "delayMillis=10}}");
+    }
+
+    @Test
+    public void animationParametersToString() {
+        assertThat(
+                new AnimationParameters.Builder()
+                        .setDurationMillis(100)
+                        .setEasing(new CubicBezierEasing.Builder().setX1(3f).build())
+                        .setDelayMillis(20)
+                        .build()
+                        .toString())
+                .isEqualTo(
+                        "AnimationParameters{durationMillis=100, easing=CubicBezierEasing{x1=3.0, "
+                                + "y1=0.0, x2=0.0, y2=0.0}, delayMillis=20}");
+    }
 }
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicBoolTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicBoolTest.java
index 7c51d3e..b9bf7e3 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicBoolTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicBoolTest.java
@@ -98,14 +98,13 @@
   public void negateOpBool() {
     DynamicBool firstBool = DynamicBool.constant(true);
 
-    assertThat(firstBool.isTrue().toDynamicBoolProto()).isEqualTo(firstBool.toDynamicBoolProto());
-    assertThat(firstBool.isFalse().toDynamicBoolProto().getNotOp().getInput())
+    assertThat(firstBool.negate().toDynamicBoolProto().getNotOp().getInput())
         .isEqualTo(firstBool.toDynamicBoolProto());
   }
 
   @Test
   public void logicalToString() {
-    assertThat(DynamicBool.constant(true).isFalse().toString())
+    assertThat(DynamicBool.constant(true).negate().toString())
         .isEqualTo("NotBoolOp{input=FixedBool{value=true}}");
   }
 
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicColorTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicColorTest.java
index 83cae56..9f03379 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicColorTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicColorTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertThrows;
 
 import androidx.annotation.ColorInt;
+import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.Repeatable;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
@@ -34,8 +35,11 @@
   @ColorInt private static final int CONSTANT_VALUE = 0xff00ff00;
   private static final AnimationSpec SPEC =
       new AnimationSpec.Builder()
-          .setStartDelayMillis(1)
-          .setDurationMillis(2)
+          .setAnimationParameters(
+                  new AnimationParameters.Builder()
+                          .setDurationMillis(2)
+                          .setDelayMillis(1)
+                          .build())
           .setRepeatable(
               new Repeatable.Builder().setRepeatMode(REPEAT_MODE_REVERSE).setIterations(10).build())
           .build();
@@ -90,12 +94,12 @@
             DynamicColor.animate(
                     /* start= */ 0x00000001,
                     /* end= */ 0x00000002,
-                    new AnimationSpec.Builder().setStartDelayMillis(0).build())
+                    new AnimationSpec.Builder().build())
                 .toString())
         .isEqualTo(
             "AnimatableFixedColor{"
                 + "fromArgb=1, toArgb=2, animationSpec=AnimationSpec{"
-                + "durationMillis=0, startDelayMillis=0, easing=null, repeatable=null}}");
+                + "animationParameters=null, repeatable=null}}");
   }
 
   @Test
@@ -121,12 +125,16 @@
     assertThat(
             DynamicColor.animate(
                     /* stateKey= */ "key",
-                    new AnimationSpec.Builder().setStartDelayMillis(1).build())
+                    new AnimationSpec.Builder()
+                            .setAnimationParameters(
+                                    new AnimationParameters.Builder().setDelayMillis(1).build())
+                            .build())
                 .toString())
         .isEqualTo(
             "AnimatableDynamicColor{"
                 + "input=StateColorSource{sourceKey=key}, animationSpec=AnimationSpec{"
-                + "durationMillis=0, startDelayMillis=1, easing=null, repeatable=null}}");
+                + "animationParameters=AnimationParameters{durationMillis=0, easing=null, "
+                + "delayMillis=1}, repeatable=null}}");
   }
 
   @Test
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
index 281eb6a..d00b7f3 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
@@ -17,206 +17,236 @@
 package androidx.wear.protolayout.expression;
 
 import static androidx.wear.protolayout.expression.AnimationParameterBuilders.REPEAT_MODE_REVERSE;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
 
+import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DynamicFloatTest {
-  private static final String STATE_KEY = "state-key";
-  private static final float CONSTANT_VALUE = 42.42f;
-  private static final AnimationSpec SPEC =
-      new AnimationSpec.Builder()
-          .setStartDelayMillis(1)
-          .setDurationMillis(2)
-          .setRepeatable(
-              new AnimationParameterBuilders.Repeatable.Builder()
-                  .setRepeatMode(REPEAT_MODE_REVERSE)
-                  .setIterations(10)
-                  .build())
-          .build();
+    private static final String STATE_KEY = "state-key";
+    private static final float CONSTANT_VALUE = 42.42f;
+    private static final AnimationSpec SPEC =
+            new AnimationSpec.Builder()
+                    .setAnimationParameters(
+                            new AnimationParameters.Builder()
+                                    .setDurationMillis(2)
+                                    .setDelayMillis(1)
+                                    .build())
+                    .setRepeatable(
+                            new AnimationParameterBuilders.Repeatable.Builder()
+                                    .setRepeatMode(REPEAT_MODE_REVERSE)
+                                    .setIterations(10)
+                                    .build())
+                    .build();
 
-  @Test
-  public void constantFloat() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void constantFloat() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    assertThat(constantFloat.toDynamicFloatProto().getFixed().getValue())
-        .isWithin(0.0001f)
-        .of(CONSTANT_VALUE);
-  }
+        assertThat(constantFloat.toDynamicFloatProto().getFixed().getValue())
+                .isWithin(0.0001f)
+                .of(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantToString() {
-    assertThat(DynamicFloat.constant(1f).toString()).isEqualTo("FixedFloat{value=1.0}");
-  }
+    @Test
+    public void constantToString() {
+        assertThat(DynamicFloat.constant(1f).toString()).isEqualTo("FixedFloat{value=1.0}");
+    }
 
-  @Test
-  public void stateEntryValueFloat() {
-    DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
+    @Test
+    public void stateEntryValueFloat() {
+        DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
 
-    assertThat(stateFloat.toDynamicFloatProto().getStateSource().getSourceKey())
-        .isEqualTo(STATE_KEY);
-  }
+        assertThat(stateFloat.toDynamicFloatProto().getStateSource().getSourceKey())
+                .isEqualTo(STATE_KEY);
+    }
 
-  @Test
-  public void stateToString() {
-    assertThat(DynamicFloat.fromState("key").toString())
-        .isEqualTo("StateFloatSource{sourceKey=key}");
-  }
+    @Test
+    public void stateToString() {
+        assertThat(DynamicFloat.fromState("key").toString())
+                .isEqualTo("StateFloatSource{sourceKey=key}");
+    }
 
-  @Test
-  public void constantFloat_asInt() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void constantFloat_asInt() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    DynamicInt32 dynamicInt32 = constantFloat.asInt();
+        DynamicInt32 dynamicInt32 = constantFloat.asInt();
 
-    assertThat(dynamicInt32.toDynamicInt32Proto().getFloatToInt().getInput().getFixed().getValue())
-        .isWithin(0.0001f)
-        .of(CONSTANT_VALUE);
-  }
+        assertThat(
+                        dynamicInt32
+                                .toDynamicInt32Proto()
+                                .getFloatToInt()
+                                .getInput()
+                                .getFixed()
+                                .getValue())
+                .isWithin(0.0001f)
+                .of(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantFloat_asIntToString() {
-    assertThat(DynamicFloat.constant(1f).asInt().toString())
-        .isEqualTo("FloatToInt32Op{input=FixedFloat{value=1.0}, roundMode=1}");
-  }
+    @Test
+    public void constantFloat_asIntToString() {
+        assertThat(DynamicFloat.constant(1f).asInt().toString())
+                .isEqualTo("FloatToInt32Op{input=FixedFloat{value=1.0}, roundMode=1}");
+    }
 
-  @Test
-  public void formatFloat_defaultParameters() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void formatFloat_defaultParameters() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    DynamicString defaultFormat = constantFloat.format();
+        DynamicString defaultFormat = constantFloat.format();
 
-    DynamicProto.FloatFormatOp floatFormatOp =
-        defaultFormat.toDynamicStringProto().getFloatFormatOp();
-    assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
-    assertThat(floatFormatOp.getGroupingUsed()).isFalse();
-    assertThat(floatFormatOp.hasMaxFractionDigits()).isFalse();
-    assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(0);
-    assertThat(floatFormatOp.hasMinIntegerDigits()).isFalse();
-  }
+        DynamicProto.FloatFormatOp floatFormatOp =
+                defaultFormat.toDynamicStringProto().getFloatFormatOp();
+        assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
+        assertThat(floatFormatOp.getGroupingUsed()).isFalse();
+        assertThat(floatFormatOp.hasMaxFractionDigits()).isFalse();
+        assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(0);
+        assertThat(floatFormatOp.hasMinIntegerDigits()).isFalse();
+    }
 
-  @Test
-  public void formatFloat_customFormatter() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
-    boolean groupingUsed = true;
-    int minFractionDigits = 1;
-    int maxFractionDigits = 2;
-    int minIntegerDigits = 3;
-    DynamicFloat.FloatFormatter floatFormatter =
-        DynamicFloat.FloatFormatter.with()
-            .minFractionDigits(minFractionDigits)
-            .maxFractionDigits(maxFractionDigits)
-            .minIntegerDigits(minIntegerDigits)
-            .groupingUsed(groupingUsed);
+    @Test
+    public void formatFloat_customFormatter() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+        boolean groupingUsed = true;
+        int minFractionDigits = 1;
+        int maxFractionDigits = 2;
+        int minIntegerDigits = 3;
+        DynamicFloat.FloatFormatter floatFormatter =
+                new DynamicFloat.FloatFormatter.Builder()
+                        .setMinFractionDigits(minFractionDigits)
+                        .setMaxFractionDigits(maxFractionDigits)
+                        .setMinIntegerDigits(minIntegerDigits)
+                        .setGroupingUsed(groupingUsed)
+                        .build();
 
-    DynamicString customFormat = constantFloat.format(floatFormatter);
+        DynamicString customFormat = constantFloat.format(floatFormatter);
 
-    DynamicProto.FloatFormatOp floatFormatOp =
-        customFormat.toDynamicStringProto().getFloatFormatOp();
-    assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
-    assertThat(floatFormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
-    assertThat(floatFormatOp.getMaxFractionDigits()).isEqualTo(maxFractionDigits);
-    assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(minFractionDigits);
-    assertThat(floatFormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
-  }
+        DynamicProto.FloatFormatOp floatFormatOp =
+                customFormat.toDynamicStringProto().getFloatFormatOp();
+        assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
+        assertThat(floatFormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
+        assertThat(floatFormatOp.getMaxFractionDigits()).isEqualTo(maxFractionDigits);
+        assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(minFractionDigits);
+        assertThat(floatFormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
+    }
 
-  @Test
-  public void formatToString() {
-    assertThat(
-            DynamicFloat.constant(1f)
-                .format(
-                    DynamicFloat.FloatFormatter.with()
-                        .maxFractionDigits(2)
-                        .minFractionDigits(3)
-                        .minIntegerDigits(4)
-                        .groupingUsed(true))
-                .toString())
-        .isEqualTo(
-            "FloatFormatOp{input=FixedFloat{value=1.0}, maxFractionDigits=2, "
-                + "minFractionDigits=3, minIntegerDigits=4, groupingUsed=true}");
-  }
+    @Test
+    public void formatToString() {
+        assertThat(
+                        DynamicFloat.constant(1f)
+                                .format(
+                                        new DynamicFloat.FloatFormatter.Builder()
+                                                .setMaxFractionDigits(2)
+                                                .setMinFractionDigits(3)
+                                                .setMinIntegerDigits(4)
+                                                .setGroupingUsed(true)
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "FloatFormatOp{input=FixedFloat{value=1.0}, maxFractionDigits=2, "
+                                + "minFractionDigits=3, minIntegerDigits=4, groupingUsed=true}");
+    }
 
-  @Test
-  public void rangeAnimatedFloat() {
-    float startFloat = 100f;
-    float endFloat = 200f;
+    @Test
+    public void rangeAnimatedFloat() {
+        float startFloat = 100f;
+        float endFloat = 200f;
 
-    DynamicFloat animatedFloat = DynamicFloat.animate(startFloat, endFloat);
-    DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(startFloat, endFloat, SPEC);
+        DynamicFloat animatedFloat = DynamicFloat.animate(startFloat, endFloat);
+        DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(startFloat, endFloat, SPEC);
 
-    assertThat(animatedFloat.toDynamicFloatProto().getAnimatableFixed().hasAnimationSpec())
-        .isFalse();
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getFromValue())
-        .isEqualTo(startFloat);
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getToValue())
-        .isEqualTo(endFloat);
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getAnimationSpec())
-        .isEqualTo(SPEC.toProto());
-  }
+        assertThat(animatedFloat.toDynamicFloatProto().getAnimatableFixed().hasAnimationSpec())
+                .isFalse();
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getFromValue())
+                .isEqualTo(startFloat);
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getToValue())
+                .isEqualTo(endFloat);
+        assertThat(
+                        animatedFloatWithSpec
+                                .toDynamicFloatProto()
+                                .getAnimatableFixed()
+                                .getAnimationSpec())
+                .isEqualTo(SPEC.toProto());
+    }
 
-  @Test
-  public void rangeAnimatedToString() {
-    assertThat(
-            DynamicFloat.animate(
-                    /* start= */ 1f,
-                    /* end= */ 2f,
-                    new AnimationSpec.Builder().setStartDelayMillis(0).build())
-                .toString())
-        .isEqualTo(
-            "AnimatableFixedFloat{fromValue=1.0, toValue=2.0, animationSpec=AnimationSpec{"
-                + "durationMillis=0, startDelayMillis=0, easing=null, repeatable=null}}");
-  }
+    @Test
+    public void rangeAnimatedToString() {
+        assertThat(
+                        DynamicFloat.animate(
+                                        /* start= */ 1f,
+                                        /* end= */ 2f,
+                                        new AnimationSpec.Builder().build())
+                                .toString())
+                .isEqualTo(
+                        "AnimatableFixedFloat{fromValue=1.0, toValue=2.0,"
+                                + " animationSpec=AnimationSpec{animationParameters=null,"
+                                + " repeatable=null}}");
+    }
 
-  @Test
-  public void stateAnimatedFloat() {
-    DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
+    @Test
+    public void stateAnimatedFloat() {
+        DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
 
-    DynamicFloat animatedFloat = DynamicFloat.animate(STATE_KEY);
-    DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(STATE_KEY, SPEC);
+        DynamicFloat animatedFloat = DynamicFloat.animate(STATE_KEY);
+        DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(STATE_KEY, SPEC);
 
-    assertThat(animatedFloat.toDynamicFloatProto().getAnimatableDynamic().hasAnimationSpec())
-        .isFalse();
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getInput())
-        .isEqualTo(stateFloat.toDynamicFloatProto());
-    assertThat(
-            animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getAnimationSpec()
-    ).isEqualTo(SPEC.toProto());
-    assertThat(animatedFloat.toDynamicFloatProto())
-        .isEqualTo(stateFloat.animate().toDynamicFloatProto());
-  }
+        assertThat(animatedFloat.toDynamicFloatProto().getAnimatableDynamic().hasAnimationSpec())
+                .isFalse();
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getInput())
+                .isEqualTo(stateFloat.toDynamicFloatProto());
+        assertThat(
+                        animatedFloatWithSpec
+                                .toDynamicFloatProto()
+                                .getAnimatableDynamic()
+                                .getAnimationSpec())
+                .isEqualTo(SPEC.toProto());
+        assertThat(animatedFloat.toDynamicFloatProto())
+                .isEqualTo(stateFloat.animate().toDynamicFloatProto());
+    }
 
-  @Test
-  public void stateAnimatedToString() {
-    assertThat(
-            DynamicFloat.animate(
-                    /* stateKey= */ "key",
-                    new AnimationSpec.Builder().setStartDelayMillis(1).build())
-                .toString())
-        .isEqualTo(
-            "AnimatableDynamicFloat{"
-                + "input=StateFloatSource{sourceKey=key}, animationSpec=AnimationSpec{"
-                + "durationMillis=0, startDelayMillis=1, easing=null, repeatable=null}}");
-  }
+    @Test
+    public void stateAnimatedToString() {
+        assertThat(
+                        DynamicFloat.animate(
+                                        /* stateKey= */ "key",
+                                        new AnimationSpec.Builder()
+                                                .setAnimationParameters(
+                                                        new AnimationParameters.Builder()
+                                                                .setDelayMillis(1)
+                                                                .build())
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "AnimatableDynamicFloat{input=StateFloatSource{sourceKey=key},"
+                                + " animationSpec=AnimationSpec{animationParameters"
+                                + "=AnimationParameters{durationMillis=0,"
+                                + " easing=null, delayMillis=1}, repeatable=null}}");
+    }
 
-  @Test
-  public void validProto() {
-    DynamicFloat from = DynamicFloat.constant(CONSTANT_VALUE);
-    DynamicFloat to = DynamicFloat.fromByteArray(from.toDynamicFloatByteArray());
+    @Test
+    public void validProto() {
+        DynamicFloat from = DynamicFloat.constant(CONSTANT_VALUE);
+        DynamicFloat to = DynamicFloat.fromByteArray(from.toDynamicFloatByteArray());
 
-    assertThat(to.toDynamicFloatProto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(to.toDynamicFloatProto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void invalidProto() {
-    assertThrows(IllegalArgumentException.class, () -> DynamicFloat.fromByteArray(new byte[] {1}));
-  }
+    @Test
+    public void invalidProto() {
+        assertThrows(
+                IllegalArgumentException.class, () -> DynamicFloat.fromByteArray(new byte[] {1}));
+    }
 }
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
index 416e35b..f87e5b5 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
@@ -17,120 +17,130 @@
 package androidx.wear.protolayout.expression;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
 
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DynamicInt32Test {
-  private static final String STATE_KEY = "state-key";
-  private static final int CONSTANT_VALUE = 42;
+    private static final String STATE_KEY = "state-key";
+    private static final int CONSTANT_VALUE = 42;
 
-  @Test
-  public void constantInt32() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void constantInt32() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    assertThat(constantInt32.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(constantInt32.toDynamicInt32Proto().getFixed().getValue())
+                .isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantToString() {
-    assertThat(DynamicInt32.constant(1).toString()).isEqualTo("FixedInt32{value=1}");
-  }
+    @Test
+    public void constantToString() {
+        assertThat(DynamicInt32.constant(1).toString()).isEqualTo("FixedInt32{value=1}");
+    }
 
-  @Test
-  public void stateEntryValueInt32() {
-    DynamicInt32 stateInt32 = DynamicInt32.fromState(STATE_KEY);
+    @Test
+    public void stateEntryValueInt32() {
+        DynamicInt32 stateInt32 = DynamicInt32.fromState(STATE_KEY);
 
-    assertThat(stateInt32.toDynamicInt32Proto().getStateSource().getSourceKey())
-        .isEqualTo(STATE_KEY);
-  }
+        assertThat(stateInt32.toDynamicInt32Proto().getStateSource().getSourceKey())
+                .isEqualTo(STATE_KEY);
+    }
 
-  @Test
-  public void stateToString() {
-    assertThat(DynamicInt32.fromState("key").toString())
-        .isEqualTo("StateInt32Source{sourceKey=key}");
-  }
+    @Test
+    public void stateToString() {
+        assertThat(DynamicInt32.fromState("key").toString())
+                .isEqualTo("StateInt32Source{sourceKey=key}");
+    }
 
-  @Test
-  public void constantInt32_asFloat() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void constantInt32_asFloat() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    DynamicFloat dynamicFloat = constantInt32.asFloat();
+        DynamicFloat dynamicFloat = constantInt32.asFloat();
 
-    assertThat(
-            dynamicFloat
-                .toDynamicFloatProto()
-                .getInt32ToFloatOperation()
-                .getInput()
-                .getFixed()
-                .getValue())
-        .isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(
+                        dynamicFloat
+                                .toDynamicFloatProto()
+                                .getInt32ToFloatOperation()
+                                .getInput()
+                                .getFixed()
+                                .getValue())
+                .isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantInt32_asFloatToString() {
-    assertThat(DynamicInt32.constant(1).asFloat().toString())
-        .isEqualTo("Int32ToFloatOp{input=FixedInt32{value=1}}");
-  }
+    @Test
+    public void constantInt32_asFloatToString() {
+        assertThat(DynamicInt32.constant(1).asFloat().toString())
+                .isEqualTo("Int32ToFloatOp{input=FixedInt32{value=1}}");
+    }
 
-  @Test
-  public void formatInt32_defaultParameters() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void formatInt32_defaultParameters() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    DynamicBuilders.DynamicString defaultFormat = constantInt32.format();
+        DynamicBuilders.DynamicString defaultFormat = constantInt32.format();
 
-    DynamicProto.Int32FormatOp int32FormatOp =
-        defaultFormat.toDynamicStringProto().getInt32FormatOp();
-    assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
-    assertThat(int32FormatOp.getGroupingUsed()).isFalse();
-    assertThat(int32FormatOp.hasMinIntegerDigits()).isFalse();
-  }
+        DynamicProto.Int32FormatOp int32FormatOp =
+                defaultFormat.toDynamicStringProto().getInt32FormatOp();
+        assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
+        assertThat(int32FormatOp.getGroupingUsed()).isFalse();
+        assertThat(int32FormatOp.hasMinIntegerDigits()).isFalse();
+    }
 
-  @Test
-  public void formatInt32_customFormatter() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
-    boolean groupingUsed = true;
-    int minIntegerDigits = 3;
-    DynamicInt32.IntFormatter intFormatter =
-        DynamicInt32.IntFormatter.with()
-            .minIntegerDigits(minIntegerDigits)
-            .groupingUsed(groupingUsed);
+    @Test
+    public void formatInt32_customFormatter() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+        boolean groupingUsed = true;
+        int minIntegerDigits = 3;
+        DynamicInt32.IntFormatter intFormatter =
+                new DynamicInt32.IntFormatter.Builder()
+                        .setMinIntegerDigits(minIntegerDigits)
+                        .setGroupingUsed(groupingUsed)
+                        .build();
 
-    DynamicBuilders.DynamicString customFormat = constantInt32.format(intFormatter);
+        DynamicBuilders.DynamicString customFormat = constantInt32.format(intFormatter);
 
-    DynamicProto.Int32FormatOp int32FormatOp =
-        customFormat.toDynamicStringProto().getInt32FormatOp();
-    assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
-    assertThat(int32FormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
-    assertThat(int32FormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
-  }
+        DynamicProto.Int32FormatOp int32FormatOp =
+                customFormat.toDynamicStringProto().getInt32FormatOp();
+        assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
+        assertThat(int32FormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
+        assertThat(int32FormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
+    }
 
-  @Test
-  public void formatToString() {
-    assertThat(
-            DynamicInt32.constant(1)
-                .format(DynamicInt32.IntFormatter.with().minIntegerDigits(2).groupingUsed(true))
-                .toString())
-        .isEqualTo(
-            "Int32FormatOp{input=FixedInt32{value=1}, minIntegerDigits=2, groupingUsed=true}");
-  }
+    @Test
+    public void formatToString() {
+        assertThat(
+                        DynamicInt32.constant(1)
+                                .format(
+                                        new DynamicInt32.IntFormatter.Builder()
+                                                .setMinIntegerDigits(2)
+                                                .setGroupingUsed(true)
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "Int32FormatOp{input=FixedInt32{value=1}, minIntegerDigits=2,"
+                            + " groupingUsed=true}");
+    }
 
-  @Test
-  public void validProto() {
-    DynamicInt32 from = DynamicInt32.constant(CONSTANT_VALUE);
-    DynamicInt32 to = DynamicInt32.fromByteArray(from.toDynamicInt32ByteArray());
+    @Test
+    public void validProto() {
+        DynamicInt32 from = DynamicInt32.constant(CONSTANT_VALUE);
+        DynamicInt32 to = DynamicInt32.fromByteArray(from.toDynamicInt32ByteArray());
 
-    assertThat(to.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(to.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void invalidProto() {
-    assertThrows(IllegalArgumentException.class, () -> DynamicInt32.fromByteArray(new byte[] {1}));
-  }
+    @Test
+    public void invalidProto() {
+        assertThrows(
+                IllegalArgumentException.class, () -> DynamicInt32.fromByteArray(new byte[] {1}));
+    }
 }
diff --git a/wear/protolayout/protolayout-material/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout-material/api/public_plus_experimental_current.txt
index 862495c3..cd20621 100644
--- a/wear/protolayout/protolayout-material/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout-material/api/public_plus_experimental_current.txt
@@ -159,6 +159,7 @@
   public class Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
     method public static androidx.wear.protolayout.material.Text? fromLayoutElement(androidx.wear.protolayout.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.protolayout.ColorBuilders.ColorProp getColor();
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public boolean getExcludeFontPadding();
     method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle getFontStyle();
     method public float getLineHeight();
     method public int getMaxLines();
@@ -175,6 +176,7 @@
     ctor public Text.Builder(android.content.Context, String);
     method public androidx.wear.protolayout.material.Text build();
     method public androidx.wear.protolayout.material.Text.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.material.Text.Builder setExcludeFontPadding(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setItalic(boolean);
     method public androidx.wear.protolayout.material.Text.Builder setMaxLines(@IntRange(from=1) int);
     method public androidx.wear.protolayout.material.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
diff --git a/wear/protolayout/protolayout-material/build.gradle b/wear/protolayout/protolayout-material/build.gradle
index 536215b..042384d 100644
--- a/wear/protolayout/protolayout-material/build.gradle
+++ b/wear/protolayout/protolayout-material/build.gradle
@@ -25,9 +25,9 @@
 dependencies {
     annotationProcessor(libs.nullaway)
     api("androidx.annotation:annotation:1.2.0")
-    implementation(project(":wear:protolayout:protolayout"))
+    api(project(":wear:protolayout:protolayout"))
     implementation(project(":wear:protolayout:protolayout-proto"))
-    implementation(project(":wear:protolayout:protolayout-expression"))
+    implementation("androidx.annotation:annotation-experimental:1.3.0")
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testExtJunit)
diff --git a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
index cb43b9b..3653dc9 100644
--- a/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
+++ b/wear/protolayout/protolayout-material/src/androidTest/java/androidx/wear/protolayout/material/TestCasesGenerator.java
@@ -32,7 +32,9 @@
 import androidx.wear.protolayout.LayoutElementBuilders.Box;
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement;
 import androidx.wear.protolayout.LayoutElementBuilders.Row;
+import androidx.wear.protolayout.ModifiersBuilders.Background;
 import androidx.wear.protolayout.ModifiersBuilders.Clickable;
+import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -181,7 +183,7 @@
                         .setChipColors(ChipDefaults.SECONDARY_COLORS)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
                         .setCustomContent(
-                                new Row.Builder()
+                                new LayoutElementBuilders.Row.Builder()
                                         .addContent(
                                                 new Text.Builder(context, "text1")
                                                         .setTypography(Typography.TYPOGRAPHY_TITLE3)
@@ -278,6 +280,30 @@
         testCases.put(
                 "default_text_golden" + goldenSuffix, new Text.Builder(context, "Testing").build());
         testCases.put(
+                "excluded_padding_text_golden" + goldenSuffix,
+                new Row.Builder()
+                        .addContent(
+                                new Box.Builder()
+                                        .setModifiers(buildBackgroundColorModifier(Color.YELLOW))
+                                        .addContent(
+                                                new Text.Builder(context, "Inc padd ")
+                                                        .setExcludeFontPadding(false)
+                                                        .setTypography(
+                                                                Typography.TYPOGRAPHY_CAPTION1)
+                                                        .build())
+                                        .build())
+                        .addContent(
+                                new Box.Builder()
+                                        .setModifiers(buildBackgroundColorModifier(Color.CYAN))
+                                        .addContent(
+                                                new Text.Builder(context, "Excl padd")
+                                                        .setExcludeFontPadding(true)
+                                                        .setTypography(
+                                                                Typography.TYPOGRAPHY_CAPTION1)
+                                                        .build())
+                                        .build())
+                        .build());
+        testCases.put(
                 "custom_text_golden" + goldenSuffix,
                 new Text.Builder(context, "Testing text.")
                         .setItalic(true)
@@ -291,4 +317,10 @@
 
         return testCases;
     }
+
+    private static Modifiers buildBackgroundColorModifier(int color) {
+        return new Modifiers.Builder()
+                .setBackground(new Background.Builder().setColor(argb(color)).build())
+                .build();
+    }
 }
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Button.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Button.java
index 494c7a21e..40309f1c 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Button.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Button.java
@@ -44,13 +44,13 @@
 import androidx.wear.protolayout.LayoutElementBuilders.ColorFilter;
 import androidx.wear.protolayout.LayoutElementBuilders.Image;
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement;
-import androidx.wear.protolayout.ModifiersBuilders;
 import androidx.wear.protolayout.ModifiersBuilders.Background;
 import androidx.wear.protolayout.ModifiersBuilders.Clickable;
 import androidx.wear.protolayout.ModifiersBuilders.Corner;
 import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata;
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
 import androidx.wear.protolayout.ModifiersBuilders.Semantics;
+import androidx.wear.protolayout.TypeBuilders.StringProp;
 import androidx.wear.protolayout.expression.Fingerprint;
 import androidx.wear.protolayout.material.Typography.TypographyName;
 import androidx.wear.protolayout.proto.LayoutElementProto;
@@ -315,7 +315,7 @@
                                             .build());
             if (mContentDescription.length() > 0) {
                 modifiers.setSemantics(
-                        new ModifiersBuilders.Semantics.Builder()
+                        new Semantics.Builder()
                                 .setContentDescription(mContentDescription.toString())
                                 .build());
             }
@@ -476,7 +476,11 @@
         if (semantics == null) {
             return null;
         }
-        return semantics.getContentDescription();
+        StringProp contentDescriptionProp = semantics.getContentDescription();
+        if (contentDescriptionProp == null) {
+            return null;
+        }
+        return contentDescriptionProp.getValue();
     }
 
     /** Returns size for this Button. */
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
index 4683c7a..1674976 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Chip.java
@@ -61,6 +61,7 @@
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
 import androidx.wear.protolayout.ModifiersBuilders.Padding;
 import androidx.wear.protolayout.ModifiersBuilders.Semantics;
+import androidx.wear.protolayout.TypeBuilders.StringProp;
 import androidx.wear.protolayout.expression.Fingerprint;
 import androidx.wear.protolayout.material.Typography.TypographyName;
 import androidx.wear.protolayout.proto.LayoutElementProto;
@@ -555,7 +556,11 @@
         if (semantics == null) {
             return null;
         }
-        return semantics.getContentDescription();
+        StringProp contentDescriptionProp = semantics.getContentDescription();
+        if (contentDescriptionProp == null) {
+            return null;
+        }
+        return contentDescriptionProp.getValue();
     }
 
     /** Returns custom content from this Chip if it has been added. Otherwise, it returns null. */
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CircularProgressIndicator.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CircularProgressIndicator.java
index 9a5e955..adf018f 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CircularProgressIndicator.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/CircularProgressIndicator.java
@@ -42,11 +42,11 @@
 import androidx.wear.protolayout.LayoutElementBuilders.ArcLine;
 import androidx.wear.protolayout.LayoutElementBuilders.ArcSpacer;
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement;
-import androidx.wear.protolayout.ModifiersBuilders;
 import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata;
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
 import androidx.wear.protolayout.ModifiersBuilders.Padding;
 import androidx.wear.protolayout.ModifiersBuilders.Semantics;
+import androidx.wear.protolayout.TypeBuilders.StringProp;
 import androidx.wear.protolayout.expression.Fingerprint;
 import androidx.wear.protolayout.proto.LayoutElementProto;
 
@@ -214,7 +214,7 @@
 
             if (mContentDescription.length() > 0) {
                 modifiers.setSemantics(
-                        new ModifiersBuilders.Semantics.Builder()
+                        new Semantics.Builder()
                                 .setContentDescription(mContentDescription.toString())
                                 .build());
             }
@@ -305,7 +305,11 @@
         if (semantics == null) {
             return null;
         }
-        return semantics.getContentDescription();
+        StringProp contentDescriptionProp = semantics.getContentDescription();
+        if (contentDescriptionProp == null) {
+            return null;
+        }
+        return contentDescriptionProp.getValue();
     }
 
     /**
diff --git a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
index 132990b..6c8a631 100644
--- a/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
+++ b/wear/protolayout/protolayout-material/src/main/java/androidx/wear/protolayout/material/Text.java
@@ -24,6 +24,7 @@
 import static androidx.wear.protolayout.material.Typography.getFontStyleBuilder;
 import static androidx.wear.protolayout.material.Typography.getLineHeightForTypography;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 
 import androidx.annotation.IntRange;
@@ -40,6 +41,7 @@
 import androidx.wear.protolayout.LayoutElementBuilders.TextOverflow;
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
 import androidx.wear.protolayout.expression.Fingerprint;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
 import androidx.wear.protolayout.material.Typography.TypographyName;
 import androidx.wear.protolayout.proto.LayoutElementProto;
 
@@ -79,18 +81,20 @@
     /** Builder class for {@link Text}. */
     public static final class Builder implements LayoutElement.Builder {
         @NonNull private final Context mContext;
-        @NonNull private String mTextContent = "";
         @NonNull private ColorProp mColor = argb(Colors.DEFAULT.getOnPrimary());
         private @TypographyName int mTypographyName = TYPOGRAPHY_DISPLAY1;
         private boolean mItalic = false;
-        private int mMaxLines = 1;
         private boolean mUnderline = false;
-        @TextAlignment private int mMultilineAlignment = TEXT_ALIGN_CENTER;
-        @NonNull private Modifiers mModifiers = new Modifiers.Builder().build();
-        private @TextOverflow int mOverflow = TEXT_OVERFLOW_ELLIPSIZE_END;
         private boolean mIsScalable = true;
         @Nullable private Integer mCustomWeight = null;
 
+        @NonNull
+        private final LayoutElementBuilders.Text.Builder mElementBuilder =
+                new LayoutElementBuilders.Text.Builder()
+                        .setMaxLines(1)
+                        .setMultilineAlignment(TEXT_ALIGN_CENTER)
+                        .setOverflow(TEXT_OVERFLOW_ELLIPSIZE_END);
+
         /**
          * Creates a builder for {@link Text}.
          *
@@ -99,7 +103,7 @@
          */
         public Builder(@NonNull Context context, @NonNull String text) {
             mContext = context;
-            mTextContent = text;
+            mElementBuilder.setText(text);
         }
 
         /**
@@ -152,7 +156,7 @@
         /** Sets the maximum lines of text. If not set, 1 will be used. */
         @NonNull
         public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
-            this.mMaxLines = maxLines;
+            this.mElementBuilder.setMaxLines(maxLines);
             return this;
         }
 
@@ -164,14 +168,14 @@
          */
         @NonNull
         public Builder setMultilineAlignment(@TextAlignment int multilineAlignment) {
-            this.mMultilineAlignment = multilineAlignment;
+            this.mElementBuilder.setMultilineAlignment(multilineAlignment);
             return this;
         }
 
         /** Sets the modifiers of text. */
         @NonNull
         public Builder setModifiers(@NonNull Modifiers modifiers) {
-            this.mModifiers = modifiers;
+            this.mElementBuilder.setModifiers(modifiers);
             return this;
         }
 
@@ -181,7 +185,7 @@
          */
         @NonNull
         public Builder setOverflow(@TextOverflow int overflow) {
-            this.mOverflow = overflow;
+            this.mElementBuilder.setOverflow(overflow);
             return this;
         }
 
@@ -195,6 +199,24 @@
             return this;
         }
 
+        /**
+         * Sets whether the {@link Text} excludes extra top and bottom padding above the normal
+         * ascent and descent. The default is false.
+         */
+        // TODO(b/252767963): Coordinate the transition of the default from false->true along with
+        // other impacted UI Libraries - needs care as will have an impact on layout and needs to be
+        // communicated clearly.
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @ProtoLayoutExperimental
+        public Builder setExcludeFontPadding(boolean excludeFontPadding) {
+            this.mElementBuilder.setAndroidTextStyle(
+                    new LayoutElementBuilders.AndroidTextStyle.Builder()
+                            .setExcludeFontPadding(excludeFontPadding)
+                            .build());
+            return this;
+        }
+
         /** Constructs and returns {@link Text} with the provided content and look. */
         @NonNull
         @Override
@@ -207,17 +229,10 @@
             if (mCustomWeight != null) {
                 fontStyleBuilder.setWeight(mCustomWeight);
             }
-
-            LayoutElementBuilders.Text.Builder text =
-                    new LayoutElementBuilders.Text.Builder()
-                            .setText(mTextContent)
-                            .setFontStyle(fontStyleBuilder.build())
-                            .setLineHeight(getLineHeightForTypography(mTypographyName))
-                            .setMaxLines(mMaxLines)
-                            .setMultilineAlignment(mMultilineAlignment)
-                            .setModifiers(mModifiers)
-                            .setOverflow(mOverflow);
-            return new Text(text.build());
+            mElementBuilder
+                    .setFontStyle(fontStyleBuilder.build())
+                    .setLineHeight(getLineHeightForTypography(mTypographyName));
+            return new Text(mElementBuilder.build());
         }
     }
 
@@ -284,6 +299,15 @@
     }
 
     /**
+     * Returns whether the Text has extra top and bottom padding above the normal ascent and descent
+     * excluded.
+     */
+    @ProtoLayoutExperimental
+    public boolean getExcludeFontPadding() {
+        return checkNotNull(mText.getAndroidTextStyle()).getExcludeFontPadding();
+    }
+
+    /**
      * Returns Material Text object from the given LayoutElement (e.g. one retrieved from a
      * container's content with {@code container.getContents().get(index)}) if that element can be
      * converted to Material Text. Otherwise, it will return null.
diff --git a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
index 3f424d0..a63dd69 100644
--- a/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
+++ b/wear/protolayout/protolayout-material/src/test/java/androidx/wear/protolayout/material/TextTest.java
@@ -45,6 +45,7 @@
 import androidx.wear.protolayout.ModifiersBuilders.Background;
 import androidx.wear.protolayout.ModifiersBuilders.ElementMetadata;
 import androidx.wear.protolayout.ModifiersBuilders.Modifiers;
+import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -111,19 +112,20 @@
     public void testWrongTag() {
         Box box =
                 new Box.Builder()
-                    .setModifiers(
-                        new Modifiers.Builder()
-                            .setMetadata(
-                                new ElementMetadata.Builder()
-                                    .setTagData("test".getBytes(UTF_8))
-                                    .build())
-                            .build())
-                    .build();
+                        .setModifiers(
+                                new Modifiers.Builder()
+                                        .setMetadata(
+                                                new ElementMetadata.Builder()
+                                                        .setTagData("test".getBytes(UTF_8))
+                                                        .build())
+                                        .build())
+                        .build();
 
         assertThat(Text.fromLayoutElement(box)).isNull();
     }
 
     @Test
+    @ProtoLayoutExperimental
     public void testText() {
         String textContent = "Testing text.";
         Modifiers modifiers =
@@ -142,6 +144,7 @@
                         .setOverflow(TEXT_OVERFLOW_ELLIPSIZE_END)
                         .setMultilineAlignment(TEXT_ALIGN_END)
                         .setWeight(FONT_WEIGHT_BOLD)
+                        .setExcludeFontPadding(true)
                         .build();
 
         FontStyle expectedFontStyle =
@@ -162,6 +165,7 @@
         assertThat(Text.fromLayoutElement(text)).isEqualTo(text);
     }
 
+    @ProtoLayoutExperimental
     private void assertTextIsEqual(
             Text actualText,
             String expectedTextContent,
@@ -176,6 +180,7 @@
         assertThat(actualText.getMaxLines()).isEqualTo(2);
         assertThat(actualText.getLineHeight())
                 .isEqualTo(getLineHeightForTypography(TYPOGRAPHY_TITLE1).getValue());
+        assertThat(actualText.getExcludeFontPadding()).isTrue();
     }
 
     private void assertFontStyle(
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/animation_parameters.proto b/wear/protolayout/protolayout-proto/src/main/proto/animation_parameters.proto
index 5581a04..c607956 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/animation_parameters.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/animation_parameters.proto
@@ -10,21 +10,47 @@
 message AnimationSpec {
   // The duration of the animation in milliseconds. If not set, defaults to
   // 300ms.
+  // @deprecated Use animation_parameters instead.
   uint32 duration_millis = 1;
 
   // The delay to start the animation in milliseconds. If not set, defaults to
   // 0.
+  // @deprecated Use animation_parameters instead.
   uint32 start_delay_millis = 2;
 
   // The easing to be used for adjusting an animation's fraction. If not set,
   // defaults to Linear Interpolator.
+  // @deprecated Use animation_parameters instead.
   Easing easing = 3;
 
+  // Animation parameters including duration, easing and repeat delay.
+  AnimationParameters animation_parameters = 4;
+
   // The repeatable mode to be used for specifying repetition parameters for the
   // animation. If not set, animation won't be repeated.
   Repeatable repeatable = 5;
 }
 
+// Animation specs of duration, easing and repeat delay.
+message AnimationParameters {
+  // The duration of the animation in milliseconds. If not set, defaults to
+  // 300ms.
+  uint32 duration_millis = 1;
+
+  // The easing to be used for adjusting an animation's fraction. If not set,
+  // defaults to Linear Interpolator.
+  Easing easing = 2;
+
+  // Animation delay in millis.
+  oneof optional_delay_millis {
+    // Animation delay in millis. When used outside repeatable, this is the
+    // delay to start the animation in milliseconds. When set inside repeatable,
+    // this is the delay before repeating animation in milliseconds. If not set,
+    // no delay will be applied.
+    uint32 delay_millis = 3;
+  }
+}
+
 // The easing to be used for adjusting an animation's fraction. This allows
 // animation to speed up and slow down, rather than moving at a constant rate.
 // If not set, defaults to Linear Interpolator.
@@ -69,12 +95,15 @@
   // set, defaults to restart.
   RepeatMode repeat_mode = 2;
 
-  // The delay before the forward part of the repeat in milliseconds. If not set, defaults to 0.
-  uint32 forward_repeat_delay_millis = 3;
+  reserved 3, 4, 5;
 
-  // The delay before the reversed part of the repeat in milliseconds. This delay will not be used
-  // when the repeat mode is restart. If not set, defaults to 0.
-  uint32 reverse_repeat_delay_millis = 4;
+  // Optional custom parameters for the forward passes of animation. If not set,
+  // use the main animation parameters set outside of Repeatable.
+  AnimationParameters forward_repeat_override = 6;
+
+  // Optional custom parameters for the reverse passes of animation. If not set,
+  // use the main animation parameters set outside of Repeatable.
+  AnimationParameters reverse_repeat_override = 7;
 }
 
 // The repeat mode to specify how animation will behave when repeated.
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/dynamic.proto b/wear/protolayout/protolayout-proto/src/main/proto/dynamic.proto
index 67d6ff8..23ab73a 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/dynamic.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/dynamic.proto
@@ -507,6 +507,20 @@
   AnimationSpec animation_spec = 3;
 }
 
+// A conditional operator which yields a color depending on the boolean
+// operand. This implements:
+// ```color result = condition ? value_if_true : value_if_false```
+message ConditionalColorOp {
+    // The condition to use.
+  DynamicBool condition = 1;
+
+  // The color to yield if condition is true.
+  DynamicColor value_if_true = 2;
+
+  // The color to yield if condition is false.
+  DynamicColor value_if_false = 3;
+}
+
 // A dynamic color type.
 message DynamicColor {
   oneof inner {
@@ -514,6 +528,7 @@
     StateColorSource state_source = 2;
     AnimatableFixedColor animatable_fixed = 3;
     AnimatableDynamicColor animatable_dynamic = 4;
+    ConditionalColorOp conditional_op = 5;
   }
 }
 
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
index 9e083fc..fe23db4 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -142,11 +142,20 @@
   TextOverflow value = 1;
 }
 
+// Parameters for Marquee animation. Only applies for TEXT_OVERFLOW_MARQUEE.
+message MarqueeParameters {
+  oneof optional_iterations {
+    // The number of times to repeat the Marquee animation. Set to -1 to repeat
+    // indefinitely. Defaults to repeat indefinitely.
+    int32 iterations = 1;
+  }
+}
+
 // An Android platform specific text style configuration options for styling and
 // compatibility.
 message AndroidTextStyle {
-  // Whether the Text excludes extra top and bottom padding above the normal
-  // ascent and descent. The default is false.
+  // Whether the Text excludes padding specified by the font, i.e. extra top and bottom padding
+  // above the normal ascent and descent. The default is false.
   bool exclude_font_padding = 1;
 }
 
@@ -180,6 +189,10 @@
   // be truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
   TextOverflowProp overflow = 6;
 
+  // Parameters for Marquee animation. Only applies when overflow is
+  // TEXT_OVERFLOW_MARQUEE.
+  MarqueeParameters marquee_parameters = 9;
+
   // The explicit height between lines of text. This is equivalent to the
   // vertical distance between subsequent baselines. If not specified, defaults
   // the font's recommended interline spacing.
@@ -387,6 +400,10 @@
   // TEXT_OVERFLOW_TRUNCATE.
   TextOverflowProp overflow = 5;
 
+  // Parameters for Marquee animation. Only applies when overflow is
+  // TEXT_OVERFLOW_MARQUEE.
+  MarqueeParameters marquee_parameters = 8;
+
   // Extra spacing to add between each line. This will apply to all
   // spans regardless of their font size. This is in addition to original
   // line heights. Note that this won't add any additional space before the
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index e7ea4bc1..f449584 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -31,7 +31,7 @@
 
     implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
     implementation(project(":wear:protolayout:protolayout-expression"))
-    implementation(project(":wear:protolayout:protolayout-expression-pipeline"))
+    api(project(":wear:protolayout:protolayout-expression-pipeline"))
     implementation "androidx.concurrent:concurrent-futures:1.1.0"
     implementation("androidx.core:core:1.7.0")
     implementation("androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01")
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutTheme.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutTheme.java
index 74c0a40..b6836ab 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutTheme.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutTheme.java
@@ -24,10 +24,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 
-/**
- * Theme customization for ProtoLayout texts, which includes Font types and variants.
- *
- */
+/** Theme customization for ProtoLayout texts, which includes Font types and variants. */
 @RestrictTo(Scope.LIBRARY)
 public interface ProtoLayoutTheme {
 
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutVisibilityState.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutVisibilityState.java
index 214535a..64654d5 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutVisibilityState.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/ProtoLayoutVisibilityState.java
@@ -23,10 +23,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-/**
- * The visibility state of the layout.
- *
- */
+/** The visibility state of the layout. */
 @IntDef({
     ProtoLayoutVisibilityState.VISIBILITY_STATE_FULLY_VISIBLE,
     ProtoLayoutVisibilityState.VISIBILITY_STATE_PARTIALLY_VISIBLE,
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/common/ProtoLayoutDiffer.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/common/ProtoLayoutDiffer.java
index e5a30d5..906634e 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/common/ProtoLayoutDiffer.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/common/ProtoLayoutDiffer.java
@@ -35,16 +35,13 @@
 import java.util.Collections;
 import java.util.List;
 
-/**
- * Utility to diff 2 proto layouts in order to be able to partially update the display.
- *
- */
+/** Utility to diff 2 proto layouts in order to be able to partially update the display. */
 @RestrictTo(Scope.LIBRARY_GROUP)
 public class ProtoLayoutDiffer {
     /** Prefix for all node IDs generated by this differ. */
     @NonNull private static final String NODE_ID_PREFIX = "pT";
 
-    /** Node ID of the root node. @hide */
+    /** Node ID of the root node. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
     public static final String ROOT_NODE_ID = NODE_ID_PREFIX + "1";
@@ -55,7 +52,6 @@
     /**
      * If true, an element addition or removal forces its parent (and siblings of the changed node)
      * to reinflate.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final boolean UPDATE_ALL_CHILDREN_AFTER_ADD_REMOVE = true;
@@ -63,7 +59,6 @@
     /**
      * Index of the first child node under a parent. {@link #createNodePosId} should be called
      * starting from this value and incremented by one for each child node.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final int FIRST_CHILD_INDEX = 0;
@@ -118,10 +113,7 @@
         }
     }
 
-    /**
-     * A node in a layout tree, that has a change compared to a previous version.
-     *
-     */
+    /** A node in a layout tree, that has a change compared to a previous version. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class TreeNodeWithChange {
         @NonNull private final TreeNode mTreeNode;
@@ -135,7 +127,6 @@
         /**
          * Returns the linear {@link LayoutElement} that this node represents, or null if the node
          * isn't for a {@link LayoutElement}.
-         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -146,7 +137,6 @@
         /**
          * Returns the radial {@link ArcLayoutElement} that this node represents, or null if the
          * node isn't for a {@link ArcLayoutElement}.
-         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -154,7 +144,7 @@
             return mTreeNode.mArcLayoutElement;
         }
 
-        /** Returns the fingerprint for this node. @hide */
+        /** Returns the fingerprint for this node. */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
         public NodeFingerprint getFingerprint() {
@@ -164,7 +154,6 @@
         /**
          * Returns an ID for this node based on its position in the tree. Only comparable against
          * other position IDs that are generated with {@link #createNodePosId}.
-         *
          */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -175,7 +164,6 @@
         /**
          * Returns true if the change in this node affects the node itself only. Otherwise the
          * change affects both the node and its children.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         public boolean isSelfOnlyChange() {
@@ -183,7 +171,7 @@
         }
     }
 
-    /** A diff in layout, containing information about the tree nodes that have changed. @hide */
+    /** A diff in layout, containing information about the tree nodes that have changed. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class LayoutDiff {
         @NonNull private final List<TreeNodeWithChange> mChangedNodes;
@@ -195,7 +183,6 @@
         /**
          * An ordered list of nodes that have changed. A changed node always comes before its
          * changed descendants in this list.
-         *
          */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -285,7 +272,7 @@
         return new LayoutDiff(changedNodes);
     }
 
-    /** Check whether 2 nodes represented by the given fingerprints are equivalent. @hide */
+    /** Check whether 2 nodes represented by the given fingerprints are equivalent. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static boolean areNodesEquivalent(
             @NonNull NodeFingerprint nodeA, @NonNull NodeFingerprint nodeB) {
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
index 20538ab..3a0ce8f 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/NodeInfo.java
@@ -123,10 +123,7 @@
         mResolvedAvds.forEach(ResolvedAvd::unregisterCallback);
     }
 
-    /**
-     * Returns the number of active bound dynamic types.
-     *
-     */
+    /** Returns the number of active bound dynamic types. */
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     @SuppressWarnings("RestrictTo")
     int size() {
@@ -204,10 +201,7 @@
         return null;
     }
 
-    /**
-     * Returns how many animations are running.
-     *
-     */
+    /** Returns how many animations are running. */
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     @SuppressWarnings("RestrictTo")
     int getRunningAnimationCount() {
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
index 54b87ee4..fc45546 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipeline.java
@@ -74,7 +74,6 @@
  *
  * <p>Given a dynamic ProtoLayout data source, this builds up a {@link BoundDynamicType}, which can
  * source the required data, and transform it into its final form.
- *
  */
 @RestrictTo(Scope.LIBRARY_GROUP)
 public class ProtoLayoutDynamicDataPipeline {
@@ -92,10 +91,7 @@
     @NonNull final QuotaManager mAnimationQuotaManager;
     @NonNull private final DynamicTypeEvaluator mEvaluator;
 
-    /**
-     * Creates a {@link ProtoLayoutDynamicDataPipeline} without animation support.
-     *
-     */
+    /** Creates a {@link ProtoLayoutDynamicDataPipeline} without animation support. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public ProtoLayoutDynamicDataPipeline(
             boolean canUpdateGateways,
@@ -113,7 +109,6 @@
     /**
      * Creates a {@link ProtoLayoutDynamicDataPipeline} with animation support. Maximum number of
      * concurrently running animations is defined in the given {@link QuotaManager}.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public ProtoLayoutDynamicDataPipeline(
@@ -151,10 +146,7 @@
         this.mEvaluator = new DynamicTypeEvaluator(evaluatorConfigBuilder.build());
     }
 
-    /**
-     * Returns the number of active dynamic types in this pipeline.
-     *
-     */
+    /** Returns the number of active dynamic types in this pipeline. */
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     @RestrictTo(Scope.TESTS)
     public int size() {
@@ -172,10 +164,7 @@
         mPositionIdTree.removeChildNodesFor(posId);
     }
 
-    /**
-     * Build {@link PipelineMaker}.
-     *
-     */
+    /** Build {@link PipelineMaker}. */
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
     public PipelineMaker newPipelineMaker(
@@ -187,7 +176,6 @@
     /**
      * Test version of the {@link #newPipelineMaker(BiFunction, BiFunction)} without animation
      * inflators.
-     *
      */
     @VisibleForTesting
     @NonNull
@@ -201,7 +189,6 @@
     /**
      * Sets whether this proto layout can perform updates. If the proto layout cannot update, then
      * updates through the data pipeline (e.g. health updates) will be suppressed.
-     *
      */
     @UiThread
     @SuppressWarnings("RestrictTo")
@@ -214,10 +201,7 @@
         }
     }
 
-    /**
-     * Closes existing gateways.
-     *
-     */
+    /** Closes existing gateways. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @SuppressWarnings("RestrictTo")
     public void close() {
@@ -234,7 +218,6 @@
      * <p>The nodes are accumulated and can be committed to the pipeline.
      *
      * <p>Note that this class is not thread-safe.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class PipelineMaker {
@@ -464,7 +447,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -483,7 +465,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -499,7 +480,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -516,7 +496,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -533,7 +512,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -550,7 +528,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -566,7 +543,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -583,7 +559,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -599,7 +574,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -616,7 +590,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -633,7 +606,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -649,7 +621,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @SuppressWarnings("RestrictTo")
         @NonNull
@@ -658,12 +629,7 @@
                 @NonNull DpProp dpProp,
                 @NonNull String posId,
                 @NonNull DynamicTypeValueReceiver<Float> consumer) {
-            BoundDynamicType node;
-            if (dpProp.hasValue()) {
-                node = mEvaluator.bind(dpProp.getDynamicValue(), consumer, dpProp.getValue());
-            } else {
-                node = mEvaluator.bind(dpProp.getDynamicValue(), consumer);
-            }
+            BoundDynamicType node = mEvaluator.bind(dpProp.getDynamicValue(), consumer);
             getNodeInfo(posId).addBoundType(node);
             return this;
         }
@@ -671,7 +637,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -680,14 +645,7 @@
                 @NonNull DegreesProp degreesProp,
                 @NonNull String posId,
                 @NonNull DynamicTypeValueReceiver<Float> consumer) {
-            BoundDynamicType node;
-            if (degreesProp.hasValue()) {
-                node =
-                        mEvaluator.bind(
-                                degreesProp.getDynamicValue(), consumer, degreesProp.getValue());
-            } else {
-                node = mEvaluator.bind(degreesProp.getDynamicValue(), consumer);
-            }
+            BoundDynamicType node = mEvaluator.bind(degreesProp.getDynamicValue(), consumer);
             getNodeInfo(posId).addBoundType(node);
             return this;
         }
@@ -695,7 +653,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -704,12 +661,7 @@
                 @NonNull ColorProp colorProp,
                 @NonNull String posId,
                 @NonNull DynamicTypeValueReceiver<Integer> consumer) {
-            BoundDynamicType node;
-            if (colorProp.hasArgb()) {
-                node = mEvaluator.bind(colorProp.getDynamicValue(), consumer, colorProp.getArgb());
-            } else {
-                node = mEvaluator.bind(colorProp.getDynamicValue(), consumer);
-            }
+            BoundDynamicType node = mEvaluator.bind(colorProp.getDynamicValue(), consumer);
             getNodeInfo(posId).addBoundType(node);
             return this;
         }
@@ -717,7 +669,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -733,7 +684,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -750,7 +700,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressWarnings("RestrictTo")
@@ -764,10 +713,7 @@
                     colorProp, posId, buildStateUpdateCallback(invalidData, consumer));
         }
 
-        /**
-         * This store method shall be called during the layout inflation in a background thread.
-         *
-         */
+        /** This store method shall be called during the layout inflation in a background thread. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @SuppressLint("CheckReturnValue") // (b/247804720)
         @NonNull
@@ -787,7 +733,6 @@
         /**
          * This store method shall be called during the layout inflation in a background thread. It
          * adds given {@link DynamicBool} to the pipeline too.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -811,10 +756,7 @@
             return this;
         }
 
-        /**
-         * This store method shall be called during the layout inflation in a background thread.
-         *
-         */
+        /** This store method shall be called during the layout inflation in a background thread. */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
         public PipelineMaker addResolvedSeekableAnimatedImage(
@@ -842,10 +784,7 @@
             return this;
         }
 
-        /**
-         * Stores the {@link AnimatedVisibility} associated with the {@code posId}.
-         *
-         */
+        /** Stores the {@link AnimatedVisibility} associated with the {@code posId}. */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
         public PipelineMaker storeAnimatedVisibilityFor(
@@ -916,7 +855,6 @@
         /**
          * Add the given source to the pipeline for future evaluation. Evaluation will start when
          * {@link PipelineMaker} is committed with {@link PipelineMaker#commit}.
-         *
          */
         @NonNull
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -925,10 +863,7 @@
             return this;
         }
 
-        /**
-         * Stores a node if doesn't exist. Otherwise does nothing.
-         *
-         */
+        /** Stores a node if doesn't exist. Otherwise does nothing. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
         public PipelineMaker rememberNode(@NonNull String nodePosId) {
@@ -945,7 +880,6 @@
      *
      * <p>This method can be called directly in screenshot tests and when the renderer output is
      * never supposed to be attached to a window.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @UiThread
@@ -966,10 +900,7 @@
         mPositionIdTree.forEach(NodeInfo::initPendingBoundTypes);
     }
 
-    /**
-     * Play the animation with the given trigger type.
-     *
-     */
+    /** Play the animation with the given trigger type. */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     public void playAvdAnimations(@NonNull Trigger.InnerCase triggerCase) {
@@ -982,10 +913,7 @@
         mPositionIdTree.forEach(info -> info.setVisibility(visible));
     }
 
-    /**
-     * Reset the avd animations with the given trigger type.
-     *
-     */
+    /** Reset the avd animations with the given trigger type. */
     @UiThread
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -993,10 +921,7 @@
         mPositionIdTree.forEach(info -> info.resetAvdAnimations(triggerCase));
     }
 
-    /**
-     * Stops running avd animations and releases their quota.
-     *
-     */
+    /** Stops running avd animations and releases their quota. */
     @UiThread
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -1016,7 +941,6 @@
     /**
      * Sets visibility for resources tracked by the pipeline and plays / stops any affected
      * animations.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @UiThread
@@ -1048,7 +972,6 @@
     /**
      * Returns the total duration in milliseconds of the animated drawable associated with a
      * StateSource with the given key name; or null if no such SourceKey exists.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
@@ -1081,10 +1004,7 @@
         return affectedNodes;
     }
 
-    /**
-     * Returns how many animations are running.
-     *
-     */
+    /** Returns how many animations are running. */
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     @RestrictTo(Scope.TESTS)
     public int getRunningAnimationsCount() {
@@ -1099,10 +1019,7 @@
                         .sum();
     }
 
-    /**
-     * Returns whether all quota has been released.
-     *
-     */
+    /** Returns whether all quota has been released. */
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     @RestrictTo(Scope.TESTS)
     public boolean isAllQuotaReleased() {
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ContentUriValidator.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ContentUriValidator.java
index 99a1b281..e126046 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ContentUriValidator.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ContentUriValidator.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package androidx.wear.protolayout.renderer.inflater;
 
 import android.content.Context;
@@ -91,7 +107,7 @@
             return false;
         }
 
-        // Otherwise, only allow content from the same package that provided the layout.
+        // Otherwise, only allow content from the same package that provided the tile.
         return providerInfo.packageName.equals(mAllowedPackageName);
     }
 
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByContentUriResolver.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByContentUriResolver.java
index a19a08e..14e2fa6 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByContentUriResolver.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByContentUriResolver.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package androidx.wear.protolayout.renderer.inflater;
 
 import android.content.ContentResolver;
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByResIdResolver.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByResIdResolver.java
index 5b343d6..0989b25 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByResIdResolver.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultAndroidImageResourceByResIdResolver.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultInlineImageResourceResolver.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultInlineImageResourceResolver.java
index 8081c5b..b5714cc 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultInlineImageResourceResolver.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/DefaultInlineImageResourceResolver.java
@@ -34,9 +34,7 @@
 import java.nio.ByteBuffer;
 
 /** Resource resolver for inline resources. */
-// TODO(b/276703002): Add support for ARGB_8888 images.
 public class DefaultInlineImageResourceResolver implements InlineImageResourceResolver {
-    private static final int RGB565_BYTES_PER_PX = 2;
     private static final String TAG = "InlineImageResolver";
 
     @NonNull private final Context mAppContext;
@@ -52,7 +50,8 @@
             throws ResourceAccessException {
         @Nullable Bitmap bitmap = null;
 
-        if (inlineImage.getFormat() == ImageFormat.IMAGE_FORMAT_RGB_565) {
+        if (inlineImage.getFormat() == ImageFormat.IMAGE_FORMAT_RGB_565
+                || inlineImage.getFormat() == ImageFormat.IMAGE_FORMAT_ARGB_8888) {
             bitmap = loadRawBitmap(inlineImage);
         } else if (inlineImage.getFormat() == ImageFormat.IMAGE_FORMAT_UNDEFINED) {
             bitmap = loadStructuredBitmap(inlineImage);
@@ -72,29 +71,38 @@
         switch (imageFormat) {
             case IMAGE_FORMAT_RGB_565:
                 return Config.RGB_565;
+            case IMAGE_FORMAT_ARGB_8888:
+                return Config.ARGB_8888;
             case IMAGE_FORMAT_UNDEFINED:
             case UNRECOGNIZED:
-            case IMAGE_FORMAT_ARGB_8888:
                 return null;
         }
-
         return null;
     }
 
+    private int getBytesPerPixel(Config config) {
+        if (config == Config.RGB_565) {
+            return 2;
+        } else if (config == Config.ARGB_8888) {
+            return 4;
+        }
+        return -1;
+    }
+
     @NonNull
     private Bitmap loadRawBitmap(@NonNull InlineImageResource inlineImage)
             throws ResourceAccessException {
         Config config = imageFormatToBitmapConfig(inlineImage.getFormat());
 
-        // Only handles RGB_565 for now
-        if (config != Config.RGB_565) {
+        if (config == null) {
             throw new ResourceAccessException("Unknown image format in image resource.");
         }
 
         int widthPx = inlineImage.getWidthPx();
         int heightPx = inlineImage.getHeightPx();
 
-        int expectedDataSize = widthPx * heightPx * RGB565_BYTES_PER_PX;
+        int bytesPerPixel = getBytesPerPixel(config);
+        int expectedDataSize = widthPx * heightPx * bytesPerPixel;
         if (inlineImage.getData().size() != expectedDataSize) {
             throw new ResourceAccessException(
                     "Mismatch between image data size and dimensions in image resource.");
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 bb1546e2..625a0d7 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -126,6 +126,7 @@
 import androidx.wear.protolayout.proto.LayoutElementProto.Image;
 import androidx.wear.protolayout.proto.LayoutElementProto.Layout;
 import androidx.wear.protolayout.proto.LayoutElementProto.LayoutElement;
+import androidx.wear.protolayout.proto.LayoutElementProto.MarqueeParameters;
 import androidx.wear.protolayout.proto.LayoutElementProto.Row;
 import androidx.wear.protolayout.proto.LayoutElementProto.Spacer;
 import androidx.wear.protolayout.proto.LayoutElementProto.Span;
@@ -2105,11 +2106,16 @@
                         .applyPendingChildLayoutParams(layoutParams));
     }
 
-    private static void applyTextOverflow(TextView textView, TextOverflowProp overflow) {
+    private static void applyTextOverflow(
+            TextView textView, TextOverflowProp overflow, MarqueeParameters marqueeParameters) {
         textView.setEllipsize(textTruncationToEllipsize(overflow));
         if (overflow.getValue() == TextOverflow.TEXT_OVERFLOW_MARQUEE
                 && textView.getMaxLines() == 1) {
-            textView.setMarqueeRepeatLimit(-1); // Repeat indefinitely.
+            int marqueeIterations =
+                    marqueeParameters.hasIterations()
+                            ? marqueeParameters.getIterations()
+                            : -1; // Defaults to repeat indefinitely (-1).
+            textView.setMarqueeRepeatLimit(marqueeIterations);
             textView.setSelected(true);
             textView.setSingleLine();
             textView.setHorizontalFadingEdgeEnabled(true);
@@ -2158,7 +2164,7 @@
         } else {
             textView.setMaxLines(TEXT_MAX_LINES_DEFAULT);
         }
-        applyTextOverflow(textView, text.getOverflow());
+        applyTextOverflow(textView, text.getOverflow(), text.getMarqueeParameters());
 
         // Setting colours **must** go after setting the Text Appearance, otherwise it will get
         // immediately overridden.
@@ -2966,7 +2972,7 @@
         } else {
             tv.setMaxLines(TEXT_MAX_LINES_DEFAULT);
         }
-        applyTextOverflow(tv, spannable.getOverflow());
+        applyTextOverflow(tv, spannable.getOverflow(), spannable.getMarqueeParameters());
 
         if (spannable.hasLineHeight()) {
             // We use a Span here instead of just calling TextViewCompat#setLineHeight.
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/RatioViewWrapper.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/RatioViewWrapper.java
index 82e2803..9cca584 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/RatioViewWrapper.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/RatioViewWrapper.java
@@ -165,7 +165,7 @@
                 // This should have been picked up by the aspect ratio check above...
                 throw new IllegalStateException(
                         "Neither target width nor target height was smaller than measured"
-                            + " width/height");
+                                + " width/height");
             }
         } else if (widthMeasureMode == MeasureSpec.EXACTLY) {
             // Can't change the width, but can change height.
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ResourceResolvers.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ResourceResolvers.java
index 0b59ad9..2434d9c 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ResourceResolvers.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ResourceResolvers.java
@@ -39,7 +39,7 @@
  * common resolver implementations.
  */
 public class ResourceResolvers {
-    private final ResourceProto.Resources mProtoResources;
+    @NonNull private final ResourceProto.Resources mProtoResources;
 
     @Nullable
     private final AndroidImageResourceByResIdResolver mAndroidImageResourceByResIdResolver;
@@ -206,16 +206,18 @@
                 mProtoResources.getIdToImageMap().get(protoResourceId);
 
         if (imageResource == null) {
-            return Futures.immediateFailedFuture(new IllegalArgumentException(
-                                "Resource " + protoResourceId + " is not defined in resources bundle"));
+            return Futures.immediateFailedFuture(
+                    new IllegalArgumentException(
+                            "Resource " + protoResourceId + " is not defined in resources bundle"));
         }
 
         @Nullable
         ListenableFuture<Drawable> drawableFutureOrNull =
                 getDrawableForImageResource(imageResource);
         if (drawableFutureOrNull == null) {
-            return Futures.immediateFailedFuture(new ResourceAccessException(
-                                "Can't find resolver for image resource " + protoResourceId));
+            return Futures.immediateFailedFuture(
+                    new ResourceAccessException(
+                            "Can't find resolver for image resource " + protoResourceId));
         }
         return drawableFutureOrNull;
     }
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/SizedArcContainer.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/SizedArcContainer.java
index ad1cab0..fdd7bd4 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/SizedArcContainer.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/SizedArcContainer.java
@@ -93,8 +93,7 @@
         this(context, attrs, 0);
     }
 
-    SizedArcContainer(
-            @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+    SizedArcContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/StandardResourceResolvers.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/StandardResourceResolvers.java
index 963e769..b9ae624 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/StandardResourceResolvers.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/StandardResourceResolvers.java
@@ -16,6 +16,7 @@
 
 package androidx.wear.protolayout.renderer.inflater;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 
@@ -37,6 +38,7 @@
      * @param appContext Context for the app that both owns the resources and displays the layout.
      * @param asyncLoadExecutor The executor to use to load any async resources (e.g. Content URI).
      */
+    @SuppressLint("CheckResult")
     @NonNull
     public static ResourceResolvers.Builder forLocalApp(
             @NonNull ResourceProto.Resources protoResources,
@@ -88,7 +90,8 @@
     }
 
     /**
-     * Get a builder pre-populated with resolvers resources hosted within another app on the device.
+     * Get a builder pre-populated with resolvers for the resources of a {@link TileService}, hosted
+     * within another app on the device.
      *
      * <p>Use {@code setFooAccessor} calls to change the pre-populated ones or add others.
      *
@@ -100,6 +103,7 @@
      * @param animationEnabled Whether animation is enabled, which decides whether to load AVD
      *     resources.
      */
+    @SuppressLint("CheckResult")
     @NonNull
     public static ResourceResolvers.Builder forRemoteService(
             @NonNull ResourceProto.Resources protoResources,
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
index 473e071..e05d2cf 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/WearCurvedLineView.java
@@ -242,7 +242,8 @@
     }
 
     /** Returns the stockCap of this arc. */
-    @NonNull public Cap getStrokeCap() {
+    @NonNull
+    public Cap getStrokeCap() {
         return mCap;
     }
 
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
index 507d105..55a6de3 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/dynamicdata/ProtoLayoutDynamicDataPipelineTest.java
@@ -45,6 +45,7 @@
 import androidx.wear.protolayout.expression.pipeline.FixedQuotaManagerImpl;
 import androidx.wear.protolayout.expression.pipeline.QuotaManager;
 import androidx.wear.protolayout.expression.pipeline.StateStore;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationParameters;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.RepeatMode;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Repeatable;
@@ -159,58 +160,56 @@
     }
 
     @Test
-    public void buildPipeline_dpProp_animatable_animationsDisabled_assignsStaticValue() {
+    public void buildPipeline_dpProp_animatable_animationsDisabled_hasStaticValue_assignsEndVal() {
         List<Float> results = new ArrayList<>();
-        float staticValue = -5f;
-        DynamicFloat dynamicFloat = animatableFixedFloat(5.0f, 10.0f);
-        DpProp dpProp =
-                DpProp.newBuilder().setDynamicValue(dynamicFloat).setValue(staticValue).build();
+        float endValue = 10.0f;
+        DynamicFloat dynamicFloat = animatableFixedFloat(5.0f, endValue);
+        DpProp dpProp = DpProp.newBuilder().setDynamicValue(dynamicFloat).setValue(-5f).build();
 
         ProtoLayoutDynamicDataPipeline pipeline = initPipelineAnimationsDisabled(results, dpProp);
 
         expect.that(pipeline.getRunningAnimationsCount()).isEqualTo(0);
         expect.that(results).hasSize(1);
-        expect.that(results).containsExactly(staticValue);
+        expect.that(results).containsExactly(endValue);
     }
 
     @Test
-    public void buildPipeline_degreesProp_animatable_animationsDisabled_assignsStaticValue() {
+    public void
+            buildPipeline_degreesProp_animatable_animationsDisabled_hasStaticValue_assignsEndVal() {
         List<Float> results = new ArrayList<>();
-        float staticValue = -5f;
-        DynamicFloat dynamicFloat = animatableFixedFloat(5.0f, 10.0f);
+        float endValue = 10.0f;
+        DynamicFloat dynamicFloat = animatableFixedFloat(5.0f, endValue);
         DegreesProp degreesProp =
-                DegreesProp.newBuilder()
-                        .setDynamicValue(dynamicFloat)
-                        .setValue(staticValue)
-                        .build();
+                DegreesProp.newBuilder().setDynamicValue(dynamicFloat).setValue(-5f).build();
 
         ProtoLayoutDynamicDataPipeline pipeline =
                 initPipelineAnimationsDisabled(results, degreesProp);
 
         expect.that(pipeline.getRunningAnimationsCount()).isEqualTo(0);
         expect.that(results).hasSize(1);
-        expect.that(results).containsExactly(staticValue);
+        expect.that(results).containsExactly(endValue);
     }
 
     @Test
-    public void buildPipeline_colorProp_animatable_animationsDisabled_assignsStaticValue() {
+    public void
+            buildPipeline_colorProp_animatable_animationsDisabled_hasStaticValue_assignsEndValue() {
         List<Integer> results = new ArrayList<>();
-        int staticValue = 0x12345678;
-        DynamicColor dynamicColor = animatableFixedColor(0, 1);
+        int endValue = 1;
+        DynamicColor dynamicColor = animatableFixedColor(0, endValue);
         ColorProp colorProp =
-                ColorProp.newBuilder().setDynamicValue(dynamicColor).setArgb(staticValue).build();
+                ColorProp.newBuilder().setDynamicValue(dynamicColor).setArgb(0x12345678).build();
 
         ProtoLayoutDynamicDataPipeline pipeline =
                 initPipelineAnimationsDisabled(results, colorProp);
 
         expect.that(pipeline.getRunningAnimationsCount()).isEqualTo(0);
         expect.that(results).hasSize(1);
-        expect.that(results).containsExactly(staticValue);
+        expect.that(results).containsExactly(endValue);
     }
 
     @Test
     public void
-            buildPipeline_colorProp_animatable_animationsDisabled_noStaticValueSet_assignsEndValue() {
+            buildPipeline_colorProp_animatable_animationsDisabled_noStaticValueSet_assignsEndVal() {
         List<Integer> results = new ArrayList<>();
         DynamicColor dynamicColor = animatableFixedColor(0, 1);
         ColorProp colorProp = ColorProp.newBuilder().setDynamicValue(dynamicColor).build();
@@ -1457,8 +1456,11 @@
                                 .setToValue(to)
                                 .setAnimationSpec(
                                         AnimationSpec.newBuilder()
-                                                .setDurationMillis(duration)
-                                                .setStartDelayMillis(delay)
+                                                .setAnimationParameters(
+                                                        AnimationParameters.newBuilder()
+                                                                .setDurationMillis(duration)
+                                                                .setDelayMillis(delay)
+                                                                .build())
                                                 .build()))
                 .build();
     }
@@ -1466,6 +1468,8 @@
     @NonNull
     private DynamicFloat animatableFixedFloat(
             float from, float to, int duration, int delay, int repeatDelay, int iterations) {
+        AnimationParameters alternateParameters =
+                AnimationParameters.newBuilder().setDelayMillis(repeatDelay).build();
         return DynamicFloat.newBuilder()
                 .setAnimatableFixed(
                         AnimatableFixedFloat.newBuilder()
@@ -1473,8 +1477,11 @@
                                 .setToValue(to)
                                 .setAnimationSpec(
                                         AnimationSpec.newBuilder()
-                                                .setDurationMillis(duration)
-                                                .setStartDelayMillis(delay)
+                                                .setAnimationParameters(
+                                                        AnimationParameters.newBuilder()
+                                                                .setDurationMillis(duration)
+                                                                .setDelayMillis(delay)
+                                                                .build())
                                                 .setRepeatable(
                                                         Repeatable.newBuilder()
                                                                 .setRepeatMode(
@@ -1482,10 +1489,10 @@
                                                                                 .REPEAT_MODE_REVERSE
                                                                 )
                                                                 .setIterations(iterations)
-                                                                .setForwardRepeatDelayMillis(
-                                                                        repeatDelay)
-                                                                .setReverseRepeatDelayMillis(
-                                                                        repeatDelay)
+                                                                .setForwardRepeatOverride(
+                                                                        alternateParameters)
+                                                                .setReverseRepeatOverride(
+                                                                        alternateParameters)
                                                                 .build())
                                                 .build()))
                 .build();
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
index 52380f1..5a20188 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
@@ -74,6 +74,7 @@
 import androidx.vectordrawable.graphics.drawable.SeekableAnimatedVectorDrawable;
 import androidx.wear.protolayout.expression.pipeline.FixedQuotaManagerImpl;
 import androidx.wear.protolayout.expression.pipeline.StateStore;
+import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationParameters;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.AnimationSpec;
 import androidx.wear.protolayout.expression.proto.AnimationParameterProto.Repeatable;
 import androidx.wear.protolayout.expression.proto.DynamicProto.AnimatableDynamicFloat;
@@ -130,6 +131,7 @@
 import androidx.wear.protolayout.proto.LayoutElementProto.Image;
 import androidx.wear.protolayout.proto.LayoutElementProto.Layout;
 import androidx.wear.protolayout.proto.LayoutElementProto.LayoutElement;
+import androidx.wear.protolayout.proto.LayoutElementProto.MarqueeParameters;
 import androidx.wear.protolayout.proto.LayoutElementProto.Row;
 import androidx.wear.protolayout.proto.LayoutElementProto.Spacer;
 import androidx.wear.protolayout.proto.LayoutElementProto.Span;
@@ -1804,6 +1806,7 @@
         expect.that(tv.getEllipsize()).isEqualTo(TruncateAt.MARQUEE);
         expect.that(tv.isSelected()).isTrue();
         expect.that(tv.isHorizontalFadingEdgeEnabled()).isTrue();
+        expect.that(tv.getMarqueeRepeatLimit()).isEqualTo(-1); // Default value.
         if (VERSION.SDK_INT >= VERSION_CODES.Q) {
             expect.that(tv.isSingleLine()).isTrue();
         }
@@ -1836,6 +1839,37 @@
     }
 
     @Test
+    public void inflate_textView_marqueeAnimation_repeatLimit() {
+        String textContents = "Marquee Animation";
+        int marqueeIterations = 5;
+        LayoutElement root =
+                LayoutElement.newBuilder()
+                        .setText(
+                                Text.newBuilder()
+                                        .setText(string(textContents))
+                                        .setMaxLines(Int32Prop.newBuilder().setValue(1))
+                                        .setOverflow(
+                                                TextOverflowProp.newBuilder()
+                                                        .setValue(
+                                                                TextOverflow.TEXT_OVERFLOW_MARQUEE)
+                                                        .build())
+                                        .setMarqueeParameters(
+                                                MarqueeParameters.newBuilder()
+                                                        .setIterations(marqueeIterations)))
+                        .build();
+
+        FrameLayout rootLayout = renderer(fingerprintedLayout(root)).inflate();
+        TextView tv = (TextView) rootLayout.getChildAt(0);
+        expect.that(tv.getEllipsize()).isEqualTo(TruncateAt.MARQUEE);
+        expect.that(tv.isSelected()).isTrue();
+        expect.that(tv.isHorizontalFadingEdgeEnabled()).isTrue();
+        expect.that(tv.getMarqueeRepeatLimit()).isEqualTo(marqueeIterations);
+        if (VERSION.SDK_INT >= VERSION_CODES.Q) {
+            expect.that(tv.isSingleLine()).isTrue();
+        }
+    }
+
+    @Test
     public void inflate_spannable_marqueeAnimation() {
         String text = "Marquee Animation";
         LayoutElement root =
@@ -1859,6 +1893,41 @@
         expect.that(tv.getEllipsize()).isEqualTo(TruncateAt.MARQUEE);
         expect.that(tv.isSelected()).isTrue();
         expect.that(tv.isHorizontalFadingEdgeEnabled()).isTrue();
+        expect.that(tv.getMarqueeRepeatLimit()).isEqualTo(-1); // Default value.
+        if (VERSION.SDK_INT >= VERSION_CODES.Q) {
+            expect.that(tv.isSingleLine()).isTrue();
+        }
+    }
+
+    @Test
+    public void inflate_spannable_marqueeAnimation_repeatLimit() {
+        String text = "Marquee Animation";
+        int marqueeIterations = 5;
+        LayoutElement root =
+                LayoutElement.newBuilder()
+                        .setSpannable(
+                                Spannable.newBuilder()
+                                        .addSpans(
+                                                Span.newBuilder()
+                                                        .setText(
+                                                                SpanText.newBuilder()
+                                                                        .setText(string(text))))
+                                        .setOverflow(
+                                                TextOverflowProp.newBuilder()
+                                                        .setValue(
+                                                                TextOverflow.TEXT_OVERFLOW_MARQUEE))
+                                        .setMarqueeParameters(
+                                                MarqueeParameters.newBuilder()
+                                                        .setIterations(marqueeIterations))
+                                        .setMaxLines(Int32Prop.newBuilder().setValue(1)))
+                        .build();
+
+        FrameLayout rootLayout = renderer(fingerprintedLayout(root)).inflate();
+        TextView tv = (TextView) rootLayout.getChildAt(0);
+        expect.that(tv.getEllipsize()).isEqualTo(TruncateAt.MARQUEE);
+        expect.that(tv.isSelected()).isTrue();
+        expect.that(tv.isHorizontalFadingEdgeEnabled()).isTrue();
+        expect.that(tv.getMarqueeRepeatLimit()).isEqualTo(marqueeIterations);
         if (VERSION.SDK_INT >= VERSION_CODES.Q) {
             expect.that(tv.isSingleLine()).isTrue();
         }
@@ -4042,7 +4111,9 @@
     @NonNull
     private static FadeInTransition.Builder fadeIn(int delay) {
         return FadeInTransition.newBuilder()
-                .setAnimationSpec(AnimationSpec.newBuilder().setStartDelayMillis(delay));
+                .setAnimationSpec(
+                        AnimationSpec.newBuilder().setAnimationParameters(
+                                AnimationParameters.newBuilder().setDelayMillis(delay)));
     }
 
     private LayoutElement textFadeInSlideIn(String text) {
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 4c667bd..69c5e47 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -774,6 +774,12 @@
   }
 
   public final class ModifiersBuilders {
+    field public static final int SEMANTICS_ROLE_BUTTON = 2; // 0x2
+    field public static final int SEMANTICS_ROLE_CHECKBOX = 3; // 0x3
+    field public static final int SEMANTICS_ROLE_IMAGE = 1; // 0x1
+    field public static final int SEMANTICS_ROLE_NONE = 0; // 0x0
+    field public static final int SEMANTICS_ROLE_RADIOBUTTON = 5; // 0x5
+    field public static final int SEMANTICS_ROLE_SWITCH = 4; // 0x4
   }
 
   public static final class ModifiersBuilders.ArcModifiers {
@@ -885,13 +891,18 @@
   }
 
   public static final class ModifiersBuilders.Semantics {
-    method public String getContentDescription();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getContentDescription();
+    method public int getRole();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getStateDescription();
   }
 
   public static final class ModifiersBuilders.Semantics.Builder {
     ctor public ModifiersBuilders.Semantics.Builder();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setRole(int);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setStateDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
   }
 
   public static final class ModifiersBuilders.SpanModifiers {
diff --git a/wear/protolayout/protolayout/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
index ec7bdbf..56d09d9 100644
--- a/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
@@ -351,6 +351,7 @@
     field public static final int TEXT_ALIGN_START = 1; // 0x1
     field public static final int TEXT_ALIGN_UNDEFINED = 0; // 0x0
     field public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2; // 0x2
+    field @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final int TEXT_OVERFLOW_MARQUEE = 3; // 0x3
     field public static final int TEXT_OVERFLOW_TRUNCATE = 1; // 0x1
     field public static final int TEXT_OVERFLOW_UNDEFINED = 0; // 0x0
     field public static final int VERTICAL_ALIGN_BOTTOM = 3; // 0x3
@@ -359,6 +360,16 @@
     field public static final int VERTICAL_ALIGN_UNDEFINED = 0; // 0x0
   }
 
+  @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final class LayoutElementBuilders.AndroidTextStyle {
+    method public boolean getExcludeFontPadding();
+  }
+
+  public static final class LayoutElementBuilders.AndroidTextStyle.Builder {
+    ctor public LayoutElementBuilders.AndroidTextStyle.Builder();
+    method public androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle build();
+    method public androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle.Builder setExcludeFontPadding(boolean);
+  }
+
   public static final class LayoutElementBuilders.Arc implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
     method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getAnchorAngle();
     method public androidx.wear.protolayout.LayoutElementBuilders.ArcAnchorTypeProp? getAnchorType();
@@ -696,6 +707,7 @@
   }
 
   public static final class LayoutElementBuilders.SpanText implements androidx.wear.protolayout.LayoutElementBuilders.Span {
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle? getAndroidTextStyle();
     method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
     method public androidx.wear.protolayout.ModifiersBuilders.SpanModifiers? getModifiers();
     method public androidx.wear.protolayout.TypeBuilders.StringProp? getText();
@@ -704,6 +716,7 @@
   public static final class LayoutElementBuilders.SpanText.Builder implements androidx.wear.protolayout.LayoutElementBuilders.Span.Builder {
     ctor public LayoutElementBuilders.SpanText.Builder();
     method public androidx.wear.protolayout.LayoutElementBuilders.SpanText build();
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
     method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
     method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.SpanModifiers);
     method public androidx.wear.protolayout.LayoutElementBuilders.SpanText.Builder setText(androidx.wear.protolayout.TypeBuilders.StringProp);
@@ -722,6 +735,7 @@
 
   public static final class LayoutElementBuilders.Spannable implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
     method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+    method @IntRange(from=0xffffffff) @androidx.wear.protolayout.expression.ProtoLayoutExperimental public int getMarqueeIterations();
     method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
     method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
     method public androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignmentProp? getMultilineAlignment();
@@ -734,6 +748,7 @@
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder addSpan(androidx.wear.protolayout.LayoutElementBuilders.Span);
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable build();
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMarqueeIterations(@IntRange(from=0xffffffff) int);
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setMaxLines(@IntRange(from=1) int);
     method public androidx.wear.protolayout.LayoutElementBuilders.Spannable.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
@@ -744,9 +759,11 @@
   }
 
   public static final class LayoutElementBuilders.Text implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle? getAndroidTextStyle();
     method public androidx.wear.protolayout.LayoutElementBuilders.FontStyle? getFontStyle();
     method public androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint? getLayoutConstraintsForDynamicText();
     method public androidx.wear.protolayout.DimensionBuilders.SpProp? getLineHeight();
+    method @IntRange(from=0xffffffff) @androidx.wear.protolayout.expression.ProtoLayoutExperimental public int getMarqueeIterations();
     method public androidx.wear.protolayout.TypeBuilders.Int32Prop? getMaxLines();
     method public androidx.wear.protolayout.ModifiersBuilders.Modifiers? getModifiers();
     method public androidx.wear.protolayout.LayoutElementBuilders.TextAlignmentProp? getMultilineAlignment();
@@ -757,9 +774,11 @@
   public static final class LayoutElementBuilders.Text.Builder implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement.Builder {
     ctor public LayoutElementBuilders.Text.Builder();
     method public androidx.wear.protolayout.LayoutElementBuilders.Text build();
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setAndroidTextStyle(androidx.wear.protolayout.LayoutElementBuilders.AndroidTextStyle);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setFontStyle(androidx.wear.protolayout.LayoutElementBuilders.FontStyle);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setLayoutConstraintsForDynamicText(androidx.wear.protolayout.TypeBuilders.StringLayoutConstraint);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setLineHeight(androidx.wear.protolayout.DimensionBuilders.SpProp);
+    method @androidx.wear.protolayout.expression.ProtoLayoutExperimental public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMarqueeIterations(@IntRange(from=0xffffffff) int);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(androidx.wear.protolayout.TypeBuilders.Int32Prop);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setMaxLines(@IntRange(from=1) int);
     method public androidx.wear.protolayout.LayoutElementBuilders.Text.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.Modifiers);
@@ -802,6 +821,12 @@
   }
 
   public final class ModifiersBuilders {
+    field public static final int SEMANTICS_ROLE_BUTTON = 2; // 0x2
+    field public static final int SEMANTICS_ROLE_CHECKBOX = 3; // 0x3
+    field public static final int SEMANTICS_ROLE_IMAGE = 1; // 0x1
+    field public static final int SEMANTICS_ROLE_NONE = 0; // 0x0
+    field public static final int SEMANTICS_ROLE_RADIOBUTTON = 5; // 0x5
+    field public static final int SEMANTICS_ROLE_SWITCH = 4; // 0x4
     field @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final int SLIDE_DIRECTION_BOTTOM_TO_TOP = 4; // 0x4
     field @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final int SLIDE_DIRECTION_LEFT_TO_RIGHT = 1; // 0x1
     field @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static final int SLIDE_DIRECTION_RIGHT_TO_LEFT = 2; // 0x2
@@ -992,13 +1017,18 @@
   }
 
   public static final class ModifiersBuilders.Semantics {
-    method public String getContentDescription();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getContentDescription();
+    method public int getRole();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getStateDescription();
   }
 
   public static final class ModifiersBuilders.Semantics.Builder {
     ctor public ModifiersBuilders.Semantics.Builder();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setRole(int);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setStateDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
   }
 
   @androidx.wear.protolayout.expression.ProtoLayoutExperimental public static interface ModifiersBuilders.SlideBound {
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 4c667bd..69c5e47 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -774,6 +774,12 @@
   }
 
   public final class ModifiersBuilders {
+    field public static final int SEMANTICS_ROLE_BUTTON = 2; // 0x2
+    field public static final int SEMANTICS_ROLE_CHECKBOX = 3; // 0x3
+    field public static final int SEMANTICS_ROLE_IMAGE = 1; // 0x1
+    field public static final int SEMANTICS_ROLE_NONE = 0; // 0x0
+    field public static final int SEMANTICS_ROLE_RADIOBUTTON = 5; // 0x5
+    field public static final int SEMANTICS_ROLE_SWITCH = 4; // 0x4
   }
 
   public static final class ModifiersBuilders.ArcModifiers {
@@ -885,13 +891,18 @@
   }
 
   public static final class ModifiersBuilders.Semantics {
-    method public String getContentDescription();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getContentDescription();
+    method public int getRole();
+    method public androidx.wear.protolayout.TypeBuilders.StringProp? getStateDescription();
   }
 
   public static final class ModifiersBuilders.Semantics.Builder {
     ctor public ModifiersBuilders.Semantics.Builder();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics build();
     method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(String);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setContentDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setRole(int);
+    method public androidx.wear.protolayout.ModifiersBuilders.Semantics.Builder setStateDescription(androidx.wear.protolayout.TypeBuilders.StringProp);
   }
 
   public static final class ModifiersBuilders.SpanModifiers {
diff --git a/wear/protolayout/protolayout/build.gradle b/wear/protolayout/protolayout/build.gradle
index bc93416..27a9828 100644
--- a/wear/protolayout/protolayout/build.gradle
+++ b/wear/protolayout/protolayout/build.gradle
@@ -27,7 +27,7 @@
 
     implementation("androidx.annotation:annotation-experimental:1.3.0")
     implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
-    implementation(project(":wear:protolayout:protolayout-expression"))
+    api(project(":wear:protolayout:protolayout-expression"))
 
     compileOnly(libs.kotlinStdlib) // For annotation-experimental
 
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
index feccdaf6..ddfea03 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -24,6 +24,7 @@
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.protolayout.ColorBuilders.ColorProp;
@@ -131,28 +132,55 @@
      */
     public static final int SPAN_VERTICAL_ALIGN_TEXT_BASELINE = 2;
 
-    /** How text that will not fit inside the bounds of a {@link Text} element will be handled. */
+    /**
+     * How text that will not fit inside the bounds of a {@link Text} element will be handled.
+     *
+     * @since 1.0
+     */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
-    @IntDef({TEXT_OVERFLOW_UNDEFINED, TEXT_OVERFLOW_TRUNCATE, TEXT_OVERFLOW_ELLIPSIZE_END})
+    @IntDef({
+        TEXT_OVERFLOW_UNDEFINED,
+        TEXT_OVERFLOW_TRUNCATE,
+        TEXT_OVERFLOW_ELLIPSIZE_END,
+        TEXT_OVERFLOW_MARQUEE
+    })
     @Retention(RetentionPolicy.SOURCE)
+    @OptIn(markerClass = ProtoLayoutExperimental.class)
     public @interface TextOverflow {}
 
-    /** Overflow behavior is undefined. */
+    /**
+     * Overflow behavior is undefined.
+     *
+     * @since 1.0
+     */
     public static final int TEXT_OVERFLOW_UNDEFINED = 0;
 
     /**
      * Truncate the text to fit inside of the {@link Text} element's bounds. If text is truncated,
      * it will be truncated on a word boundary.
+     *
+     * @since 1.0
      */
     public static final int TEXT_OVERFLOW_TRUNCATE = 1;
 
     /**
      * Truncate the text to fit in the {@link Text} element's bounds, but add an ellipsis (i.e. ...)
      * to the end of the text if it has been truncated.
+     *
+     * @since 1.0
      */
     public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2;
 
     /**
+     * Enable marquee animation for texts that don't fit inside the {@link Text} element. This is
+     * only applicable for single line texts; if the text has multiple lines, the behavior is
+     * equivalent to TEXT_OVERFLOW_TRUNCATE.
+     *
+     * @since 1.2
+     */
+    @ProtoLayoutExperimental public static final int TEXT_OVERFLOW_MARQUEE = 3;
+
+    /**
      * How content which does not match the dimensions of its bounds (e.g. an image resource being
      * drawn inside an {@link Image}) will be resized to fit its bounds.
      */
@@ -639,7 +667,11 @@
         }
     }
 
-    /** An extensible {@code TextOverflow} property. */
+    /**
+     * An extensible {@code TextOverflow} property.
+     *
+     * @since 1.0
+     */
     public static final class TextOverflowProp {
         private final LayoutElementProto.TextOverflowProp mImpl;
         @Nullable private final Fingerprint mFingerprint;
@@ -650,7 +682,11 @@
             this.mFingerprint = fingerprint;
         }
 
-        /** Gets the value. Intended for testing purposes only. */
+        /**
+         * Gets the value.
+         *
+         * @since 1.0
+         */
         @TextOverflow
         public int getValue() {
             return mImpl.getValue().getNumber();
@@ -663,25 +699,46 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static TextOverflowProp fromProto(@NonNull LayoutElementProto.TextOverflowProp proto) {
-            return new TextOverflowProp(proto, null);
+        public static TextOverflowProp fromProto(
+                @NonNull LayoutElementProto.TextOverflowProp proto,
+                @Nullable Fingerprint fingerprint) {
+            return new TextOverflowProp(proto, fingerprint);
         }
 
         @NonNull
-        LayoutElementProto.TextOverflowProp toProto() {
+        static TextOverflowProp fromProto(@NonNull LayoutElementProto.TextOverflowProp proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public LayoutElementProto.TextOverflowProp toProto() {
             return mImpl;
         }
 
+        @Override
+        @NonNull
+        public String toString() {
+            return "TextOverflowProp{" + "value=" + getValue() + "}";
+        }
+
         /** Builder for {@link TextOverflowProp} */
         public static final class Builder {
             private final LayoutElementProto.TextOverflowProp.Builder mImpl =
                     LayoutElementProto.TextOverflowProp.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(1183432233);
+            private final Fingerprint mFingerprint = new Fingerprint(-1542057565);
 
             public Builder() {}
 
-            /** Sets the value. */
+            /**
+             * Sets the value.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setValue(@TextOverflow int value) {
                 mImpl.setValue(LayoutElementProto.TextOverflow.forNumber(value));
@@ -697,6 +754,187 @@
         }
     }
 
+    /**
+     * Parameters for Marquee animation. Only applies for TEXT_OVERFLOW_MARQUEE.
+     *
+     * @since 1.2
+     */
+    @ProtoLayoutExperimental
+    static final class MarqueeParameters {
+        private final LayoutElementProto.MarqueeParameters mImpl;
+        @Nullable private final Fingerprint mFingerprint;
+
+        MarqueeParameters(
+                LayoutElementProto.MarqueeParameters impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
+
+        /**
+         * Gets the number of times to repeat the Marquee animation. Set to -1 to repeat
+         * indefinitely. Defaults to repeat indefinitely.
+         *
+         * @since 1.2
+         */
+        @ProtoLayoutExperimental
+        public int getIterations() {
+            return mImpl.getIterations();
+        }
+
+        /** Get the fingerprint for this object, or null if unknown. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
+
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static MarqueeParameters fromProto(
+                @NonNull LayoutElementProto.MarqueeParameters proto,
+                @Nullable Fingerprint fingerprint) {
+            return new MarqueeParameters(proto, fingerprint);
+        }
+
+        @NonNull
+        static MarqueeParameters fromProto(@NonNull LayoutElementProto.MarqueeParameters proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public LayoutElementProto.MarqueeParameters toProto() {
+            return mImpl;
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "MarqueeParameters{" + "iterations=" + getIterations() + "}";
+        }
+
+        /** Builder for {@link MarqueeParameters} */
+        public static final class Builder {
+            private final LayoutElementProto.MarqueeParameters.Builder mImpl =
+                    LayoutElementProto.MarqueeParameters.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(1405971293);
+
+            public Builder() {}
+
+            /**
+             * Sets the number of times to repeat the Marquee animation. Set to -1 to repeat
+             * indefinitely. Defaults to repeat indefinitely.
+             *
+             * @since 1.2
+             */
+            @ProtoLayoutExperimental
+            @NonNull
+            public Builder setIterations(int iterations) {
+                mImpl.setIterations(iterations);
+                mFingerprint.recordPropertyUpdate(1, iterations);
+                return this;
+            }
+
+            /** Builds an instance from accumulated values. */
+            @NonNull
+            public MarqueeParameters build() {
+                return new MarqueeParameters(mImpl.build(), mFingerprint);
+            }
+        }
+    }
+
+    /**
+     * An Android platform specific text style configuration options for styling and compatibility.
+     *
+     * @since 1.2
+     */
+    @ProtoLayoutExperimental
+    public static final class AndroidTextStyle {
+        private final LayoutElementProto.AndroidTextStyle mImpl;
+        @Nullable private final Fingerprint mFingerprint;
+
+        AndroidTextStyle(LayoutElementProto.AndroidTextStyle impl,
+                @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
+
+        /**
+         * Gets whether the {@link Text} excludes padding specified by the font, i.e. extra top and
+         * bottom padding above the normal ascent and descent. The default is false.
+         *
+         * @since 1.2
+         */
+        public boolean getExcludeFontPadding() {
+            return mImpl.getExcludeFontPadding();
+        }
+
+        /** Get the fingerprint for this object, or null if unknown. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
+
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static AndroidTextStyle fromProto(
+                @NonNull LayoutElementProto.AndroidTextStyle proto,
+                @Nullable Fingerprint fingerprint) {
+            return new AndroidTextStyle(proto, fingerprint);
+        }
+
+        @NonNull
+        static AndroidTextStyle fromProto(@NonNull LayoutElementProto.AndroidTextStyle proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public LayoutElementProto.AndroidTextStyle toProto() {
+            return mImpl;
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "AndroidTextStyle{" + "excludeFontPadding=" + getExcludeFontPadding() + "}";
+        }
+
+        /** Builder for {@link AndroidTextStyle} */
+        public static final class Builder {
+            private final LayoutElementProto.AndroidTextStyle.Builder mImpl =
+                    LayoutElementProto.AndroidTextStyle.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(408674745);
+
+            public Builder() {}
+
+            /**
+             * Sets whether the {@link Text} excludes padding specified by the font, i.e. extra
+             * top and bottom padding above the normal ascent and descent. The default is false.
+             *
+             * @since 1.2
+             */
+            @SuppressLint("MissingGetterMatchingBuilder")
+            @NonNull
+            public Builder setExcludeFontPadding(boolean excludeFontPadding) {
+                mImpl.setExcludeFontPadding(excludeFontPadding);
+                mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(excludeFontPadding));
+                return this;
+            }
+
+            /** Builds an instance from accumulated values. */
+            @NonNull
+            public AndroidTextStyle build() {
+                return new AndroidTextStyle(mImpl.build(), mFingerprint);
+            }
+        }
+    }
+
     /** A text string. */
     public static final class Text implements LayoutElement {
         private final LayoutElementProto.Text mImpl;
@@ -818,6 +1056,34 @@
             }
         }
 
+        /**
+         * Gets an Android platform specific text style configuration options for styling and
+         * compatibility.
+         *
+         * @since 1.2
+         */
+        @ProtoLayoutExperimental
+        @Nullable
+        public AndroidTextStyle getAndroidTextStyle() {
+            if (mImpl.hasAndroidTextStyle()) {
+                return AndroidTextStyle.fromProto(mImpl.getAndroidTextStyle());
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Gets the number of times to repeat the Marquee animation. Only applies when overflow is
+         * TEXT_OVERFLOW_MARQUEE. Set to -1 to repeat indefinitely. Defaults to repeat indefinitely.
+         *
+         * @since 1.2
+         */
+        @ProtoLayoutExperimental
+        @IntRange(from = -1)
+        public int getMarqueeIterations() {
+            return mImpl.getMarqueeParameters().getIterations();
+        }
+
         @Override
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Nullable
@@ -1017,6 +1283,38 @@
                 return this;
             }
 
+            /**
+             * Sets an Android platform specific text style configuration options for styling and
+             * compatibility.
+             *
+             * @since 1.2
+             */
+            @ProtoLayoutExperimental
+            @NonNull
+            public Builder setAndroidTextStyle(@NonNull AndroidTextStyle androidTextStyle) {
+                mImpl.setAndroidTextStyle(androidTextStyle.toProto());
+                mFingerprint.recordPropertyUpdate(
+                        8, checkNotNull(androidTextStyle.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            /**
+             * Sets the number of times to repeat the Marquee animation. Only applies when overflow
+             * is TEXT_OVERFLOW_MARQUEE. Set to -1 to repeat indefinitely. Defaults to repeat
+             * indefinitely.
+             *
+             * @since 1.2
+             */
+            @ProtoLayoutExperimental
+            @NonNull
+            public Builder setMarqueeIterations(@IntRange(from = -1) int marqueeIterations) {
+                mImpl.setMarqueeParameters(
+                        LayoutElementProto.MarqueeParameters.newBuilder()
+                                .setIterations(marqueeIterations));
+                mFingerprint.recordPropertyUpdate(9, marqueeIterations);
+                return this;
+            }
+
             @Override
             @NonNull
             public Text build() {
@@ -1897,6 +2195,22 @@
             }
         }
 
+        /**
+         * Gets an Android platform specific text style configuration options for styling and
+         * compatibility.
+         *
+         * @since 1.2
+         */
+        @ProtoLayoutExperimental
+        @Nullable
+        public AndroidTextStyle getAndroidTextStyle() {
+            if (mImpl.hasAndroidTextStyle()) {
+                return AndroidTextStyle.fromProto(mImpl.getAndroidTextStyle());
+            } else {
+                return null;
+            }
+        }
+
         @Override
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Nullable
@@ -1977,6 +2291,21 @@
                 return this;
             }
 
+            /**
+             * Sets an Android platform specific text style configuration options for styling and
+             * compatibility.
+             *
+             * @since 1.2
+             */
+            @ProtoLayoutExperimental
+            @NonNull
+            public Builder setAndroidTextStyle(@NonNull AndroidTextStyle androidTextStyle) {
+                mImpl.setAndroidTextStyle(androidTextStyle.toProto());
+                mFingerprint.recordPropertyUpdate(
+                        4, checkNotNull(androidTextStyle.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
             @Override
             @NonNull
             public SpanText build() {
@@ -2314,6 +2643,18 @@
             }
         }
 
+        /**
+         * Gets the number of times to repeat the Marquee animation. Only applies when overflow is
+         * TEXT_OVERFLOW_MARQUEE. Set to -1 to repeat indefinitely. Defaults to repeat indefinitely.
+         *
+         * @since 1.2
+         */
+        @ProtoLayoutExperimental
+        @IntRange(from = -1)
+        public int getMarqueeIterations() {
+            return mImpl.getMarqueeParameters().getIterations();
+        }
+
         @Override
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Nullable
@@ -2463,6 +2804,23 @@
                 return this;
             }
 
+            /**
+             * Sets the number of times to repeat the Marquee animation. Only applies when overflow
+             * is TEXT_OVERFLOW_MARQUEE. Set to -1 to repeat indefinitely. Defaults to repeat
+             * indefinitely.
+             *
+             * @since 1.2
+             */
+            @ProtoLayoutExperimental
+            @NonNull
+            public Builder setMarqueeIterations(@IntRange(from = -1) int marqueeIterations) {
+                mImpl.setMarqueeParameters(
+                        LayoutElementProto.MarqueeParameters.newBuilder()
+                                .setIterations(marqueeIterations));
+                mFingerprint.recordPropertyUpdate(8, marqueeIterations);
+                return this;
+            }
+
             @Override
             @NonNull
             public Spannable build() {
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
index adb3aaa..9b854fd 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/ModifiersBuilders.java
@@ -30,6 +30,7 @@
 import androidx.wear.protolayout.ColorBuilders.ColorProp;
 import androidx.wear.protolayout.DimensionBuilders.DpProp;
 import androidx.wear.protolayout.TypeBuilders.BoolProp;
+import androidx.wear.protolayout.TypeBuilders.StringProp;
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
 import androidx.wear.protolayout.expression.Fingerprint;
 import androidx.wear.protolayout.expression.ProtoLayoutExperimental;
@@ -170,6 +171,69 @@
     }
 
     /**
+     * The type of user interface element. Accessibility services might use this to describe the
+     * element or do customizations.
+     *
+     * @since 1.2
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+        SEMANTICS_ROLE_NONE,
+        SEMANTICS_ROLE_IMAGE,
+        SEMANTICS_ROLE_BUTTON,
+        SEMANTICS_ROLE_CHECKBOX,
+        SEMANTICS_ROLE_SWITCH,
+        SEMANTICS_ROLE_RADIOBUTTON
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SemanticsRole {}
+
+    /**
+     * Role is undefined. It may be automatically populated.
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_NONE = 0;
+
+    /**
+     * The element is an image.
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_IMAGE = 1;
+
+    /**
+     * The element is a Button control.
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_BUTTON = 2;
+
+    /**
+     * The element is a Checkbox which is a component that represents two states (checked /
+     * unchecked).
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_CHECKBOX = 3;
+
+    /**
+     * The element is a Switch which is a two state toggleable component that provides on/off like
+     * options.
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_SWITCH = 4;
+
+    /**
+     * This element is a RadioButton which is a component to represent two states, selected and not
+     * selected.
+     *
+     * @since 1.2
+     */
+    public static final int SEMANTICS_ROLE_RADIOBUTTON = 5;
+
+    /**
      * The snap options to use when sliding using parent boundaries.
      *
      * @since 1.2
@@ -261,6 +325,8 @@
     /**
      * A modifier for an element which can have associated Actions for click events. When an element
      * with a ClickableModifier is clicked it will fire the associated action.
+     *
+     * @since 1.0
      */
     public static final class Clickable {
         private final ModifiersProto.Clickable mImpl;
@@ -271,7 +337,11 @@
             this.mFingerprint = fingerprint;
         }
 
-        /** Gets the ID associated with this action. Intended for testing purposes only. */
+        /**
+         * Gets the ID associated with this action.
+         *
+         * @since 1.0
+         */
         @NonNull
         public String getId() {
             return mImpl.getId();
@@ -279,7 +349,8 @@
 
         /**
          * Gets the action to perform when the element this modifier is attached to is clicked.
-         * Intended for testing purposes only.
+         *
+         * @since 1.0
          */
         @Nullable
         public Action getOnClick() {
@@ -297,9 +368,17 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static Clickable fromProto(
+                @NonNull ModifiersProto.Clickable proto, @Nullable Fingerprint fingerprint) {
+            return new Clickable(proto, fingerprint);
+        }
+
         @NonNull
         static Clickable fromProto(@NonNull ModifiersProto.Clickable proto) {
-            return new Clickable(proto, null);
+            return fromProto(proto, null);
         }
 
         /** Returns the internal proto instance. */
@@ -313,11 +392,15 @@
         public static final class Builder {
             private final ModifiersProto.Clickable.Builder mImpl =
                     ModifiersProto.Clickable.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(595587995);
+            private final Fingerprint mFingerprint = new Fingerprint(812136104);
 
             public Builder() {}
 
-            /** Sets the ID associated with this action. */
+            /**
+             * Sets the ID associated with this action.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setId(@NonNull String id) {
                 mImpl.setId(id);
@@ -327,6 +410,8 @@
 
             /**
              * Sets the action to perform when the element this modifier is attached to is clicked.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setOnClick(@NonNull Action onClick) {
@@ -348,6 +433,8 @@
      * A modifier for an element which has accessibility semantics associated with it. This should
      * generally be used sparingly, and in most cases should only be applied to the top-level layout
      * element or to Clickables.
+     *
+     * @since 1.0
      */
     public static final class Semantics {
         private final ModifiersProto.Semantics mImpl;
@@ -360,14 +447,49 @@
 
         /**
          * Gets the content description associated with this element. This will be dictated when the
-         * element is focused by the screen reader. Intended for testing purposes only.
+         * element is focused by the screen reader.
+         *
+         * <p>This field is made bindable from version 1.2 and will use the dynamic value (if set).
+         * Older renderers will still consider this field as non-bindable and will use the static
+         * value.
+         *
+         * @since 1.0
          */
-        @NonNull
-        public String getContentDescription() {
+        @Nullable
+        public StringProp getContentDescription() {
             if (mImpl.hasContentDescription()) {
-                return mImpl.getContentDescription().getValue();
+                return StringProp.fromProto(mImpl.getContentDescription());
+            } else {
+                return null;
             }
-            return mImpl.getObsoleteContentDescription();
+        }
+
+        /**
+         * Gets the type of user interface element. Accessibility services might use this to
+         * describe the element or do customizations.
+         *
+         * @since 1.2
+         */
+        @SemanticsRole
+        public int getRole() {
+            return mImpl.getRole().getNumber();
+        }
+
+        /**
+         * Gets the localized state description of the semantics node. For example: "on" or "off".
+         * This will be dictated when the element is focused by the screen reader.
+         *
+         * <p>This field is bindable and will use the dynamic value (if set).
+         *
+         * @since 1.2
+         */
+        @Nullable
+        public StringProp getStateDescription() {
+            if (mImpl.hasStateDescription()) {
+                return StringProp.fromProto(mImpl.getStateDescription());
+            } else {
+                return null;
+            }
         }
 
         /** Get the fingerprint for this object, or null if unknown. */
@@ -377,13 +499,23 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static Semantics fromProto(@NonNull ModifiersProto.Semantics proto) {
-            return new Semantics(proto, null);
+        public static Semantics fromProto(
+                @NonNull ModifiersProto.Semantics proto, @Nullable Fingerprint fingerprint) {
+            return new Semantics(proto, fingerprint);
         }
 
         @NonNull
-        ModifiersProto.Semantics toProto() {
+        static Semantics fromProto(@NonNull ModifiersProto.Semantics proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ModifiersProto.Semantics toProto() {
             return mImpl;
         }
 
@@ -391,15 +523,48 @@
         public static final class Builder {
             private final ModifiersProto.Semantics.Builder mImpl =
                     ModifiersProto.Semantics.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-1479823155);
+            private final Fingerprint mFingerprint = new Fingerprint(-1679805809);
 
             public Builder() {}
 
             /**
-             * Sets the content description associated with this element. This will be dictated when
-             * the element is focused by the screen reader.
+             * Sets the type of user interface element. Accessibility services might use this to
+             * describe the element or do customizations.
+             *
+             * @since 1.2
              */
             @NonNull
+            public Builder setRole(@SemanticsRole int role) {
+                mImpl.setRole(ModifiersProto.SemanticsRole.forNumber(role));
+                mFingerprint.recordPropertyUpdate(2, role);
+                return this;
+            }
+
+            /**
+             * Sets the localized state description of the semantics node. For example: "on" or
+             * "off". This will be dictated when the element is focused by the screen reader.
+             *
+             * <p>This field is bindable and will use the dynamic value (if set).
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setStateDescription(@NonNull StringProp stateDescription) {
+                mImpl.setStateDescription(stateDescription.toProto());
+                mFingerprint.recordPropertyUpdate(
+                        3, checkNotNull(stateDescription.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            /**
+             * Sets the content description associated with this element. This will be dictated when
+             * the element is focused by the screen reader.
+             *
+             * @since 1.0
+             */
+            @NonNull
+            @SuppressWarnings(
+                    "deprecation") // Updating a deprecated field for backward compatibility
             public Builder setContentDescription(@NonNull String contentDescription) {
                 mImpl.setObsoleteContentDescription(contentDescription);
                 mImpl.mergeContentDescription(
@@ -408,6 +573,27 @@
                 return this;
             }
 
+            /**
+             * Sets the content description associated with this element. This will be dictated when
+             * the element is focused by the screen reader.
+             *
+             * <p>This field is made bindable and will use the dynamic value (if set) from version
+             * 1.2 Older renderers will still consider this field as non-bindable and will use the
+             * static value.
+             *
+             * @since 1.0
+             */
+            @NonNull
+            @SuppressWarnings(
+                    "deprecation") // Updating a deprecated field for backward compatibility
+            public Builder setContentDescription(@NonNull StringProp contentDescription) {
+                mImpl.setObsoleteContentDescription(contentDescription.getValue());
+                mImpl.setContentDescription(contentDescription.toProto());
+                mFingerprint.recordPropertyUpdate(
+                        4, checkNotNull(contentDescription.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
             /** Builds an instance from accumulated values. */
             @NonNull
             public Semantics build() {
@@ -416,7 +602,11 @@
         }
     }
 
-    /** A modifier to apply padding around an element. */
+    /**
+     * A modifier to apply padding around an element.
+     *
+     * @since 1.0
+     */
     public static final class Padding {
         private final ModifiersProto.Padding mImpl;
         @Nullable private final Fingerprint mFingerprint;
@@ -428,7 +618,9 @@
 
         /**
          * Gets the padding on the end of the content, depending on the layout direction, in DP and
-         * the value of "rtl_aware". Intended for testing purposes only.
+         * the value of "rtl_aware".
+         *
+         * @since 1.0
          */
         @Nullable
         public DpProp getEnd() {
@@ -441,7 +633,9 @@
 
         /**
          * Gets the padding on the start of the content, depending on the layout direction, in DP
-         * and the value of "rtl_aware". Intended for testing purposes only.
+         * and the value of "rtl_aware".
+         *
+         * @since 1.0
          */
         @Nullable
         public DpProp getStart() {
@@ -452,7 +646,11 @@
             }
         }
 
-        /** Gets the padding at the top, in DP. Intended for testing purposes only. */
+        /**
+         * Gets the padding at the top, in DP.
+         *
+         * @since 1.0
+         */
         @Nullable
         public DpProp getTop() {
             if (mImpl.hasTop()) {
@@ -462,7 +660,11 @@
             }
         }
 
-        /** Gets the padding at the bottom, in DP. Intended for testing purposes only. */
+        /**
+         * Gets the padding at the bottom, in DP.
+         *
+         * @since 1.0
+         */
         @Nullable
         public DpProp getBottom() {
             if (mImpl.hasBottom()) {
@@ -476,7 +678,9 @@
          * Gets whether the start/end padding is aware of RTL support. If true, the values for
          * start/end will follow the layout direction (i.e. start will refer to the right hand side
          * of the container if the device is using an RTL locale). If false, start/end will always
-         * map to left/right, accordingly. Intended for testing purposes only.
+         * map to left/right, accordingly.
+         *
+         * @since 1.0
          */
         @Nullable
         public BoolProp getRtlAware() {
@@ -494,13 +698,23 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static Padding fromProto(@NonNull ModifiersProto.Padding proto) {
-            return new Padding(proto, null);
+        public static Padding fromProto(
+                @NonNull ModifiersProto.Padding proto, @Nullable Fingerprint fingerprint) {
+            return new Padding(proto, fingerprint);
         }
 
         @NonNull
-        ModifiersProto.Padding toProto() {
+        static Padding fromProto(@NonNull ModifiersProto.Padding proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ModifiersProto.Padding toProto() {
             return mImpl;
         }
 
@@ -508,13 +722,15 @@
         public static final class Builder {
             private final ModifiersProto.Padding.Builder mImpl =
                     ModifiersProto.Padding.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-1120275440);
+            private final Fingerprint mFingerprint = new Fingerprint(375605427);
 
             public Builder() {}
 
             /**
              * Sets the padding on the end of the content, depending on the layout direction, in DP
              * and the value of "rtl_aware".
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setEnd(@NonNull DpProp end) {
@@ -527,6 +743,8 @@
             /**
              * Sets the padding on the start of the content, depending on the layout direction, in
              * DP and the value of "rtl_aware".
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setStart(@NonNull DpProp start) {
@@ -536,7 +754,11 @@
                 return this;
             }
 
-            /** Sets the padding at the top, in DP. */
+            /**
+             * Sets the padding at the top, in DP.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setTop(@NonNull DpProp top) {
                 mImpl.setTop(top.toProto());
@@ -545,7 +767,11 @@
                 return this;
             }
 
-            /** Sets the padding at the bottom, in DP. */
+            /**
+             * Sets the padding at the bottom, in DP.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setBottom(@NonNull DpProp bottom) {
                 mImpl.setBottom(bottom.toProto());
@@ -559,6 +785,8 @@
              * start/end will follow the layout direction (i.e. start will refer to the right hand
              * side of the container if the device is using an RTL locale). If false, start/end will
              * always map to left/right, accordingly.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setRtlAware(@NonNull BoolProp rtlAware) {
@@ -582,7 +810,11 @@
                 return this;
             }
 
-            /** Sets the padding for all sides of the content, in DP. */
+            /**
+             * Sets the padding for all sides of the content, in DP.
+             *
+             * @since 1.0
+             */
             @NonNull
             @SuppressLint("MissingGetterMatchingBuilder")
             public Builder setAll(@NonNull DpProp value) {
@@ -597,7 +829,11 @@
         }
     }
 
-    /** A modifier to apply a border around an element. */
+    /**
+     * A modifier to apply a border around an element.
+     *
+     * @since 1.0
+     */
     public static final class Border {
         private final ModifiersProto.Border mImpl;
         @Nullable private final Fingerprint mFingerprint;
@@ -607,7 +843,11 @@
             this.mFingerprint = fingerprint;
         }
 
-        /** Gets the width of the border, in DP. Intended for testing purposes only. */
+        /**
+         * Gets the width of the border, in DP.
+         *
+         * @since 1.0
+         */
         @Nullable
         public DpProp getWidth() {
             if (mImpl.hasWidth()) {
@@ -617,7 +857,11 @@
             }
         }
 
-        /** Gets the color of the border. Intended for testing purposes only. */
+        /**
+         * Gets the color of the border.
+         *
+         * @since 1.0
+         */
         @Nullable
         public ColorProp getColor() {
             if (mImpl.hasColor()) {
@@ -634,24 +878,38 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static Border fromProto(@NonNull ModifiersProto.Border proto) {
-            return new Border(proto, null);
+        public static Border fromProto(
+                @NonNull ModifiersProto.Border proto, @Nullable Fingerprint fingerprint) {
+            return new Border(proto, fingerprint);
         }
 
         @NonNull
-        ModifiersProto.Border toProto() {
+        static Border fromProto(@NonNull ModifiersProto.Border proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ModifiersProto.Border toProto() {
             return mImpl;
         }
 
         /** Builder for {@link Border} */
         public static final class Builder {
             private final ModifiersProto.Border.Builder mImpl = ModifiersProto.Border.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(2085330827);
+            private final Fingerprint mFingerprint = new Fingerprint(157094687);
 
             public Builder() {}
 
-            /** Sets the width of the border, in DP. */
+            /**
+             * Sets the width of the border, in DP.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setWidth(@NonNull DpProp width) {
                 mImpl.setWidth(width.toProto());
@@ -666,6 +924,8 @@
              * <p>This field is made bindable and will use the dynamic value (if set) from version
              * 1.2 Older renderers will still consider this field as non-bindable and will use the
              * static value.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setColor(@NonNull ColorProp color) {
@@ -683,7 +943,11 @@
         }
     }
 
-    /** The corner of a {@link androidx.wear.protolayout.LayoutElementBuilders.Box} element. */
+    /**
+     * The corner of a {@link androidx.wear.protolayout.LayoutElementBuilders.Box} element.
+     *
+     * @since 1.0
+     */
     public static final class Corner {
         private final ModifiersProto.Corner mImpl;
         @Nullable private final Fingerprint mFingerprint;
@@ -693,7 +957,11 @@
             this.mFingerprint = fingerprint;
         }
 
-        /** Gets the radius of the corner in DP. Intended for testing purposes only. */
+        /**
+         * Gets the radius of the corner in DP.
+         *
+         * @since 1.0
+         */
         @Nullable
         public DpProp getRadius() {
             if (mImpl.hasRadius()) {
@@ -710,24 +978,38 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static Corner fromProto(@NonNull ModifiersProto.Corner proto) {
-            return new Corner(proto, null);
+        public static Corner fromProto(
+                @NonNull ModifiersProto.Corner proto, @Nullable Fingerprint fingerprint) {
+            return new Corner(proto, fingerprint);
         }
 
         @NonNull
-        ModifiersProto.Corner toProto() {
+        static Corner fromProto(@NonNull ModifiersProto.Corner proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ModifiersProto.Corner toProto() {
             return mImpl;
         }
 
         /** Builder for {@link Corner} */
         public static final class Builder {
             private final ModifiersProto.Corner.Builder mImpl = ModifiersProto.Corner.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-623478338);
+            private final Fingerprint mFingerprint = new Fingerprint(-532589910);
 
             public Builder() {}
 
-            /** Sets the radius of the corner in DP. */
+            /**
+             * Sets the radius of the corner in DP.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setRadius(@NonNull DpProp radius) {
                 mImpl.setRadius(radius.toProto());
@@ -744,7 +1026,11 @@
         }
     }
 
-    /** A modifier to apply a background to an element. */
+    /**
+     * A modifier to apply a background to an element.
+     *
+     * @since 1.0
+     */
     public static final class Background {
         private final ModifiersProto.Background mImpl;
         @Nullable private final Fingerprint mFingerprint;
@@ -756,7 +1042,9 @@
 
         /**
          * Gets the background color for this element. If not defined, defaults to being
-         * transparent. Intended for testing purposes only.
+         * transparent.
+         *
+         * @since 1.0
          */
         @Nullable
         public ColorProp getColor() {
@@ -770,7 +1058,9 @@
         /**
          * Gets the corner properties of this element. This only affects the drawing of this element
          * if it has a background color or border. If not defined, defaults to having a square
-         * corner. Intended for testing purposes only.
+         * corner.
+         *
+         * @since 1.0
          */
         @Nullable
         public Corner getCorner() {
@@ -788,13 +1078,23 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        static Background fromProto(@NonNull ModifiersProto.Background proto) {
-            return new Background(proto, null);
+        public static Background fromProto(
+                @NonNull ModifiersProto.Background proto, @Nullable Fingerprint fingerprint) {
+            return new Background(proto, fingerprint);
         }
 
         @NonNull
-        ModifiersProto.Background toProto() {
+        static Background fromProto(@NonNull ModifiersProto.Background proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public ModifiersProto.Background toProto() {
             return mImpl;
         }
 
@@ -802,7 +1102,7 @@
         public static final class Builder {
             private final ModifiersProto.Background.Builder mImpl =
                     ModifiersProto.Background.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(374507572);
+            private final Fingerprint mFingerprint = new Fingerprint(-1234051555);
 
             public Builder() {}
 
@@ -813,6 +1113,8 @@
              * <p>This field is made bindable and supports dynamic colors from version 1.2 Older
              * renderers will still consider this field as non-bindable and will use the static
              * value.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setColor(@NonNull ColorProp color) {
@@ -826,6 +1128,8 @@
              * Sets the corner properties of this element. This only affects the drawing of this
              * element if it has a background color or border. If not defined, defaults to having a
              * square corner.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setCorner(@NonNull Corner corner) {
@@ -846,6 +1150,8 @@
     /**
      * Metadata about an element. For use by libraries building higher-level components only. This
      * can be used to track component metadata.
+     *
+     * @since 1.0
      */
     public static final class ElementMetadata {
         private final ModifiersProto.ElementMetadata mImpl;
@@ -859,6 +1165,8 @@
         /**
          * Gets property describing the element with which it is associated. For use by libraries
          * building higher-level components only. This can be used to track component metadata.
+         *
+         * @since 1.0
          */
         @NonNull
         public byte[] getTagData() {
@@ -872,9 +1180,17 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static ElementMetadata fromProto(
+                @NonNull ModifiersProto.ElementMetadata proto, @Nullable Fingerprint fingerprint) {
+            return new ElementMetadata(proto, fingerprint);
+        }
+
         @NonNull
         static ElementMetadata fromProto(@NonNull ModifiersProto.ElementMetadata proto) {
-            return new ElementMetadata(proto, null);
+            return fromProto(proto, null);
         }
 
         /** Returns the internal proto instance. */
@@ -888,7 +1204,7 @@
         public static final class Builder {
             private final ModifiersProto.ElementMetadata.Builder mImpl =
                     ModifiersProto.ElementMetadata.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-589294723);
+            private final Fingerprint mFingerprint = new Fingerprint(-1401175352);
 
             public Builder() {}
 
@@ -896,6 +1212,8 @@
              * Sets property describing the element with which it is associated. For use by
              * libraries building higher-level components only. This can be used to track component
              * metadata.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setTagData(@NonNull byte[] tagData) {
@@ -916,6 +1234,8 @@
      * {@link Modifiers} for an element. These may change the way they are drawn (e.g. {@link
      * Padding} or {@link Background}), or change their behaviour (e.g. {@link Clickable}, or {@link
      * Semantics}).
+     *
+     * @since 1.0
      */
     public static final class Modifiers {
         private final ModifiersProto.Modifiers mImpl;
@@ -929,7 +1249,8 @@
         /**
          * Gets the clickable property of the modified element. It allows its wrapped element to
          * have actions associated with it, which will be executed when the element is tapped.
-         * Intended for testing purposes only.
+         *
+         * @since 1.0
          */
         @Nullable
         public Clickable getClickable() {
@@ -942,8 +1263,9 @@
 
         /**
          * Gets the semantics of the modified element. This can be used to add metadata to the
-         * modified element (eg. screen reader content descriptions). Intended for testing purposes
-         * only.
+         * modified element (eg. screen reader content descriptions).
+         *
+         * @since 1.0
          */
         @Nullable
         public Semantics getSemantics() {
@@ -954,7 +1276,11 @@
             }
         }
 
-        /** Gets the padding of the modified element. Intended for testing purposes only. */
+        /**
+         * Gets the padding of the modified element.
+         *
+         * @since 1.0
+         */
         @Nullable
         public Padding getPadding() {
             if (mImpl.hasPadding()) {
@@ -964,7 +1290,11 @@
             }
         }
 
-        /** Gets the border of the modified element. Intended for testing purposes only. */
+        /**
+         * Gets the border of the modified element.
+         *
+         * @since 1.0
+         */
         @Nullable
         public Border getBorder() {
             if (mImpl.hasBorder()) {
@@ -975,8 +1305,9 @@
         }
 
         /**
-         * Gets the background (with optional corner radius) of the modified element. Intended for
-         * testing purposes only.
+         * Gets the background (with optional corner radius) of the modified element.
+         *
+         * @since 1.0
          */
         @Nullable
         public Background getBackground() {
@@ -990,6 +1321,8 @@
         /**
          * Gets metadata about an element. For use by libraries building higher-level components
          * only. This can be used to track component metadata.
+         *
+         * @since 1.0
          */
         @Nullable
         public ElementMetadata getMetadata() {
@@ -1023,6 +1356,14 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static Modifiers fromProto(
+                @NonNull ModifiersProto.Modifiers proto, @Nullable Fingerprint fingerprint) {
+            return new Modifiers(proto, fingerprint);
+        }
+
         /**
          * Creates a new wrapper instance from the proto. Intended for testing purposes only. An
          * object created using this method can't be added to any other wrapper.
@@ -1030,7 +1371,7 @@
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
         public static Modifiers fromProto(@NonNull ModifiersProto.Modifiers proto) {
-            return new Modifiers(proto, null);
+            return fromProto(proto, null);
         }
 
         /** Returns the internal proto instance. */
@@ -1044,13 +1385,15 @@
         public static final class Builder {
             private final ModifiersProto.Modifiers.Builder mImpl =
                     ModifiersProto.Modifiers.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-170942531);
+            private final Fingerprint mFingerprint = new Fingerprint(-1165106749);
 
             public Builder() {}
 
             /**
              * Sets the clickable property of the modified element. It allows its wrapped element to
              * have actions associated with it, which will be executed when the element is tapped.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setClickable(@NonNull Clickable clickable) {
@@ -1063,6 +1406,8 @@
             /**
              * Sets the semantics of the modified element. This can be used to add metadata to the
              * modified element (eg. screen reader content descriptions).
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setSemantics(@NonNull Semantics semantics) {
@@ -1072,7 +1417,11 @@
                 return this;
             }
 
-            /** Sets the padding of the modified element. */
+            /**
+             * Sets the padding of the modified element.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setPadding(@NonNull Padding padding) {
                 mImpl.setPadding(padding.toProto());
@@ -1081,7 +1430,11 @@
                 return this;
             }
 
-            /** Sets the border of the modified element. */
+            /**
+             * Sets the border of the modified element.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setBorder(@NonNull Border border) {
                 mImpl.setBorder(border.toProto());
@@ -1090,7 +1443,11 @@
                 return this;
             }
 
-            /** Sets the background (with optional corner radius) of the modified element. */
+            /**
+             * Sets the background (with optional corner radius) of the modified element.
+             *
+             * @since 1.0
+             */
             @NonNull
             public Builder setBackground(@NonNull Background background) {
                 mImpl.setBackground(background.toProto());
@@ -1102,6 +1459,8 @@
             /**
              * Sets metadata about an element. For use by libraries building higher-level components
              * only. This can be used to track component metadata.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setMetadata(@NonNull ElementMetadata metadata) {
@@ -1189,6 +1548,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1315,6 +1675,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1432,6 +1793,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1570,6 +1932,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1714,6 +2077,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1977,6 +2341,7 @@
         public Fingerprint getFingerprint() {
             return mFingerprint;
         }
+
         /** Creates a new wrapper instance from the proto. */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -2214,6 +2579,8 @@
     /**
      * {@link Modifiers} that can be used with ArcLayoutElements. These may change the way they are
      * drawn, or change their behaviour.
+     *
+     * @since 1.0
      */
     public static final class ArcModifiers {
         private final ModifiersProto.ArcModifiers mImpl;
@@ -2226,7 +2593,9 @@
 
         /**
          * Gets allows its wrapped element to have actions associated with it, which will be
-         * executed when the element is tapped. Intended for testing purposes only.
+         * executed when the element is tapped.
+         *
+         * @since 1.0
          */
         @Nullable
         public Clickable getClickable() {
@@ -2239,7 +2608,9 @@
 
         /**
          * Gets adds metadata for the modified element, for example, screen reader content
-         * descriptions. Intended for testing purposes only.
+         * descriptions.
+         *
+         * @since 1.0
          */
         @Nullable
         public Semantics getSemantics() {
@@ -2257,9 +2628,17 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static ArcModifiers fromProto(
+                @NonNull ModifiersProto.ArcModifiers proto, @Nullable Fingerprint fingerprint) {
+            return new ArcModifiers(proto, fingerprint);
+        }
+
         @NonNull
         static ArcModifiers fromProto(@NonNull ModifiersProto.ArcModifiers proto) {
-            return new ArcModifiers(proto, null);
+            return fromProto(proto, null);
         }
 
         /** Returns the internal proto instance. */
@@ -2273,13 +2652,15 @@
         public static final class Builder {
             private final ModifiersProto.ArcModifiers.Builder mImpl =
                     ModifiersProto.ArcModifiers.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-1648736168);
+            private final Fingerprint mFingerprint = new Fingerprint(1342182166);
 
             public Builder() {}
 
             /**
              * Sets allows its wrapped element to have actions associated with it, which will be
              * executed when the element is tapped.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setClickable(@NonNull Clickable clickable) {
@@ -2292,6 +2673,8 @@
             /**
              * Sets adds metadata for the modified element, for example, screen reader content
              * descriptions.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setSemantics(@NonNull Semantics semantics) {
@@ -2313,6 +2696,8 @@
      * {@link Modifiers} that can be used with {@link
      * androidx.wear.protolayout.LayoutElementBuilders.Span} elements. These may change the way they
      * are drawn, or change their behaviour.
+     *
+     * @since 1.0
      */
     public static final class SpanModifiers {
         private final ModifiersProto.SpanModifiers mImpl;
@@ -2325,7 +2710,9 @@
 
         /**
          * Gets allows its wrapped element to have actions associated with it, which will be
-         * executed when the element is tapped. Intended for testing purposes only.
+         * executed when the element is tapped.
+         *
+         * @since 1.0
          */
         @Nullable
         public Clickable getClickable() {
@@ -2343,9 +2730,17 @@
             return mFingerprint;
         }
 
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static SpanModifiers fromProto(
+                @NonNull ModifiersProto.SpanModifiers proto, @Nullable Fingerprint fingerprint) {
+            return new SpanModifiers(proto, fingerprint);
+        }
+
         @NonNull
         static SpanModifiers fromProto(@NonNull ModifiersProto.SpanModifiers proto) {
-            return new SpanModifiers(proto, null);
+            return fromProto(proto, null);
         }
 
         /** Returns the internal proto instance. */
@@ -2359,13 +2754,15 @@
         public static final class Builder {
             private final ModifiersProto.SpanModifiers.Builder mImpl =
                     ModifiersProto.SpanModifiers.newBuilder();
-            private final Fingerprint mFingerprint = new Fingerprint(-1318656482);
+            private final Fingerprint mFingerprint = new Fingerprint(-815102194);
 
             public Builder() {}
 
             /**
              * Sets allows its wrapped element to have actions associated with it, which will be
              * executed when the element is tapped.
+             *
+             * @since 1.0
              */
             @NonNull
             public Builder setClickable(@NonNull Clickable clickable) {
diff --git a/wear/tiles/tiles-material/build.gradle b/wear/tiles/tiles-material/build.gradle
index c696e99..ac5345a 100644
--- a/wear/tiles/tiles-material/build.gradle
+++ b/wear/tiles/tiles-material/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.2.0")
-    implementation(project(":wear:tiles:tiles"))
+    api(project(":wear:tiles:tiles"))
     implementation(project(":wear:tiles:tiles-proto"))
 
     androidTestImplementation(libs.junit)
diff --git a/wear/tiles/tiles-renderer/build.gradle b/wear/tiles/tiles-renderer/build.gradle
index 1d8a312..f7841d1 100644
--- a/wear/tiles/tiles-renderer/build.gradle
+++ b/wear/tiles/tiles-renderer/build.gradle
@@ -35,7 +35,7 @@
     implementation("androidx.core:core:1.7.0")
     implementation "androidx.wear:wear:1.2.0"
 
-    implementation(project(":wear:protolayout:protolayout"))
+    api(project(":wear:protolayout:protolayout"))
     implementation(project(":wear:protolayout:protolayout-expression-pipeline"))
     implementation(project(":wear:protolayout:protolayout-renderer"))
     implementation(project(":wear:tiles:tiles"))
diff --git a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/TestWatchFaceServices.kt b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/TestWatchFaceServices.kt
index 1116fca..5a84988 100644
--- a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/TestWatchFaceServices.kt
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/TestWatchFaceServices.kt
@@ -179,6 +179,7 @@
         const val COMPLICATION_ID = 123
     }
 
+    @OptIn(ComplicationExperimental::class)
     override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ): ComplicationSlotsManager {
@@ -369,6 +370,7 @@
 
     override fun getWallpaperSurfaceHolderOverride() = surfaceHolderOverride
 
+    @OptIn(ComplicationExperimental::class)
     override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ): ComplicationSlotsManager {
@@ -650,6 +652,7 @@
 
     override fun getWallpaperSurfaceHolderOverride() = surfaceHolderOverride
 
+    @OptIn(ComplicationExperimental::class)
     override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ): ComplicationSlotsManager {
diff --git a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
index a64d494..a2a5d4b 100644
--- a/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
+++ b/wear/watchface/watchface-client/src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlClientTest.kt
@@ -883,7 +883,6 @@
         }
     }
 
-    @Ignore("b/273482617")
     @Test
     fun addWatchFaceReadyListener_alreadyReady() {
         val wallpaperService = TestExampleCanvasAnalogWatchFaceService(context, surfaceHolder)
@@ -898,7 +897,9 @@
                 { runnable -> runnable.run() },
                 { wfReady.complete(Unit) }
             )
-            assertThat(wfReady.isCompleted).isTrue()
+
+            // This should happen quickly, but it can sometimes be slow.
+            awaitWithTimeout(wfReady, 1000)
         } finally {
             interactiveInstance.close()
         }
diff --git a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
index 52bacbd..b11c186 100644
--- a/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
+++ b/wear/watchface/watchface-complications-data-source/src/main/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceService.kt
@@ -41,7 +41,15 @@
 import androidx.wear.watchface.complications.data.ComplicationDataExpressionEvaluator.Companion.hasExpression
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.data.ComplicationType.Companion.fromWireType
+import androidx.wear.watchface.complications.data.GoalProgressComplicationData
+import androidx.wear.watchface.complications.data.LongTextComplicationData
+import androidx.wear.watchface.complications.data.MonochromaticImageComplicationData
 import androidx.wear.watchface.complications.data.NoDataComplicationData
+import androidx.wear.watchface.complications.data.PhotoImageComplicationData
+import androidx.wear.watchface.complications.data.RangedValueComplicationData
+import androidx.wear.watchface.complications.data.ShortTextComplicationData
+import androidx.wear.watchface.complications.data.SmallImageComplicationData
+import androidx.wear.watchface.complications.data.WeightedElementsComplicationData
 import androidx.wear.watchface.complications.data.TimeRange
 import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.Companion.METADATA_KEY_IMMEDIATE_UPDATE_PERIOD_MILLISECONDS
 import androidx.wear.watchface.complications.datasource.ComplicationDataSourceService.ComplicationRequestListener
@@ -187,9 +195,18 @@
  *   android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST.
  * - A ComplicationDataSourceService must include a `meta-data` tag with
  *   android.support.wearable.complications.SUPPORTED_TYPES in its manifest entry. The value of this
- *   tag should be a comma separated list of types supported by the data source. Types should be
- *   given as named as per the type fields in the [ComplicationData], but omitting the "TYPE_"
- *   prefix, e.g. `SHORT_TEXT`, `LONG_TEXT`, `RANGED_VALUE`.
+ *   tag should be a comma separated list of types supported by the data source, from this table:
+ *
+ * | Androidx class                        | Tag name          |
+ * |---------------------------------------|-------------------|
+ * | [GoalProgressComplicationData]        | GOAL_PROGRESS     |
+ * | [LongTextComplicationData]            | LONG_TEXT         |
+ * | [MonochromaticImageComplicationData]  | ICON              |
+ * | [PhotoImageComplicationData]          | LARGE_IMAGE       |
+ * | [RangedValueComplicationData]         | RANGED_TEXT       |
+ * | [ShortTextComplicationData]           | SHORT_TEXT        |
+ * | [SmallImageComplicationData]          | SMALL_IMAGE       |
+ * | [WeightedElementsComplicationData]    | WEIGHTED_ELEMENTS |
  *
  * The order in which types are listed has no significance. In the case where a watch face supports
  * multiple types in a single complication slot, the watch face will determine which types it
diff --git a/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt b/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
index c88ae5e..b140ee6 100644
--- a/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
+++ b/wear/watchface/watchface-complications-data-source/src/test/java/androidx/wear/watchface/complications/datasource/ComplicationDataSourceServiceTest.kt
@@ -45,7 +45,6 @@
 import kotlin.test.assertFailsWith
 import org.junit.After
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -117,6 +116,8 @@
         /** Last error provided to [onComplicationDataError]. */
         var lastSendError: Throwable? = null
 
+        val lastPreviewOrErrorLatch = CountDownLatch(1)
+
         override var wearPlatformVersion = Build.VERSION.SDK_INT
 
         override fun createMainThreadHandler(): Handler = mPretendMainThreadHandler
@@ -139,10 +140,12 @@
 
         override fun onComplicationDataError(throwable: Throwable) {
             lastSendError = throwable
+            lastPreviewOrErrorLatch.countDown()
         }
 
         override fun getPreviewData(type: ComplicationType): ComplicationData? {
             lastPreviewType = type
+            lastPreviewOrErrorLatch.countDown()
             return previewData
         }
     }
@@ -343,7 +346,6 @@
         assertThat(data.allValues).containsExactly(null)
     }
 
-    @Ignore // b/276294993
     @Test
     fun testOnComplicationDataError() {
         val data =
@@ -359,7 +361,7 @@
             .thenThrow(error)
 
         mProvider.onUpdate(id, ComplicationType.LONG_TEXT.toWireComplicationType(), mLocalManager)
-        runUiThreadTasksWhileAwaitingDataLatch(1000)
+        mService.lastPreviewOrErrorLatch.await(1, TimeUnit.SECONDS)
 
         assertThat(mService.lastSendError).isEqualTo(error)
     }
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
index 2bbc97a..42fe7ce 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
@@ -398,7 +398,15 @@
  * displayed. If the complication is drawn with a single color it's recommended to choose
  * [monochromaticImage] and apply a tint. If the complication is rendered with multiple colors it's
  * recommended to choose the [smallImage]. It's best practice for a ComplicationDataSource to
- * specify both a [monochromaticImage] and a [smallImage].
+ * specify both a [monochromaticImage] and a [smallImage]
+ *
+ * A data source that wants to serve a ShortTextComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="SHORT_TEXT"/>
+ * ```
  *
  * @property text The body [ComplicationText] of the complication. The length of the text, including
  *   any time-dependent values at any valid time, is expected to not exceed seven characters. When
@@ -456,8 +464,10 @@
      * You must at a minimum set the [text] and [contentDescription] fields.
      *
      * @param text The main localized [ComplicationText]. This must be less than 7 characters long
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications do
+     * not have textual representation this attribute can be used for providing such. Please do not
+     * include the word 'complication' in the description.
      */
     public class Builder(
         private val text: ComplicationText,
@@ -580,6 +590,14 @@
  * recommended to choose the [smallImage]. It's best practice for a ComplicationDataSource to
  * specify both a [monochromaticImage] and a [smallImage].
  *
+ * A data source that wants to serve a LongTextComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="LONG_TEXT"/>
+ * ```
+ *
  * @property text The body [ComplicationText] of the complication. If the text is equal to
  *   [ComplicationText.PLACEHOLDER] the renderer must treat it as a placeholder rather than
  *   rendering normally, its suggested it should be rendered as a light grey box.
@@ -627,8 +645,10 @@
      *
      * @param text Localized main [ComplicationText] to display within the complication. There isn't
      *   an explicit character limit but text may be truncated if too long
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications do
+     * not have textual representation this attribute can be used for providing such. Please do not
+     * include the word 'complication' in the description.
      */
     public class Builder(
         private val text: ComplicationText,
@@ -800,6 +820,14 @@
  * recommended to choose the [smallImage]. It's best practice for a ComplicationDataSource to
  * specify both a [monochromaticImage] and a [smallImage].
  *
+ * A data source that wants to serve a RangedValueComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="GOAL_PROGRESS"/>
+ * ```
+ *
  * @property value The [Float] value of this complication which is >= [min] and <= [max] or equal to
  *   [PLACEHOLDER]. If it's equal to [PLACEHOLDER] the renderer must treat it as a placeholder
  *   rather than rendering normally, its suggested to be drawn as a grey arc with a percentage value
@@ -904,8 +932,10 @@
          * @param min The minimum value. For [TYPE_PERCENTAGE] this must be 0f.
          * @param max The maximum value. This must be less than [Float.MAX_VALUE]. For
          *   [TYPE_PERCENTAGE] this must be 0f.
-         * @param contentDescription Localized description for use by screen readers. Please do not
-         *   include the word 'complication' in the description.
+         * @param contentDescription Defines localized text that briefly describes content of the
+         * complication. This property is used primarily for accessibility. Since some complications
+         * do not have textual representation this attribute can be used for providing such. Please
+         * do not include the word 'complication' in the description.
          */
         public constructor(
             value: Float,
@@ -923,8 +953,10 @@
          * @param min The minimum value. For [TYPE_PERCENTAGE] this must be 0f.
          * @param max The maximum value. This must be less than [Float.MAX_VALUE]. For
          *   [TYPE_PERCENTAGE] this must be 0f.
-         * @param contentDescription Localized description for use by screen readers. Please do not
-         *   include the word 'complication' in the description.
+         * @param contentDescription Defines localized text that briefly describes content of the
+         * complication. This property is used primarily for accessibility. Since some complications
+         * do not have textual representation this attribute can be used for providing such. Please
+         * do not include the word 'complication' in the description.
          */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         public constructor(
@@ -1154,6 +1186,14 @@
  * [RangedValueComplicationData.TYPE_RATING] into
  * [RangedValueComplicationData.Builder.setValueType].
  *
+ * A data source that wants to serve a SmallImageComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *        android:value="GOAL_PROGRESS"/>
+ * ```
+ *
  * @property value The [Float] value of this complication which is >= 0f, this value may be larger
  *   than [targetValue]. If it's equal to [PLACEHOLDER] the renderer must treat it as a placeholder
  *   rather than rendering normally, its suggested to be drawn as a grey arc with a percentage value
@@ -1246,8 +1286,10 @@
          *
          * @param value The value of the goal complication which should be >= 0.
          * @param targetValue The target value. This must be less than [Float.MAX_VALUE].
-         * @param contentDescription Localized description for use by screen readers. Please do not
-         *   include the word 'complication' in the description.
+         * @param contentDescription Defines localized text that briefly describes content of the
+         * complication. This property is used primarily for accessibility. Since some complications
+         * do not have textual representation this attribute can be used for providing such. Please
+         * do not include the word 'complication' in the description.
          */
         public constructor(
             value: Float,
@@ -1261,8 +1303,10 @@
          * @param valueExpression The [DynamicFloat] of the goal complication which will be
          *   evaluated into a value dynamically, and should be >= 0.
          * @param targetValue The target value. This must be less than [Float.MAX_VALUE].
-         * @param contentDescription Localized description for use by screen readers. Please do not
-         *   include the word 'complication' in the description.
+         * @param contentDescription Defines localized text that briefly describes content of the
+         * complication. This property is used primarily for accessibility. Since some complications
+         * do not have textual representation this attribute can be used for providing such. Please
+         * do not include the word 'complication' in the description.
          */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         public constructor(
@@ -1449,6 +1493,14 @@
  * recommended to choose the [smallImage]. It's best practice for a ComplicationDataSource to
  * specify both a [monochromaticImage] and a [smallImage].
  *
+ * A data source that wants to serve a SmallImageComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="WEIGHTED_ELEMENTS"/>
+ * ```
+ *
  * @property elements The breakdown of the subject into various [Element]s (e.g. the proportion of
  *   calories consumed which were carbohydrates, fats, etc.). The colors need to be meaningful to
  *   the user (e.g. blue is cold, yellow/red is worm), and should be consistent with the experience
@@ -1564,8 +1616,10 @@
      *   calories consumed which were carbohydrates, fats etc... The [tapAction] must take the user
      *   to an experience where the color key becomes obvious. The maximum valid size of this list
      *   is provided by [getMaxElements].
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications
+     * do not have textual representation this attribute can be used for providing such. Please
+     * do not include the word 'complication' in the description.
      */
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public class Builder(
@@ -1739,6 +1793,14 @@
  *
  * The image is expected to always be displayed.
  *
+ * A data source that wants to serve a MonochromaticImageComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="ICON"/>
+ * ```
+ *
  * @property monochromaticImage A simple [MonochromaticImage] image that can be tinted by the watch
  *   face (typically with SRC_IN). If the monochromaticImage is equal to
  *   [MonochromaticImage.PLACEHOLDER] the renderer must treat it as a placeholder rather than
@@ -1775,8 +1837,10 @@
      * You must at a minimum set the [monochromaticImage] and [contentDescription] fields.
      *
      * @param monochromaticImage The [MonochromaticImage] to be displayed
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications
+     * do not have textual representation this attribute can be used for providing such. Please
+     * do not include the word 'complication' in the description.
      */
     public class Builder(
         private val monochromaticImage: MonochromaticImage,
@@ -1846,6 +1910,14 @@
  *
  * The image is expected to always be displayed.
  *
+ * A data source that wants to serve a SmallImageComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="SMALL_IMAGE"/>
+ * ```
+ *
  * @property smallImage The [SmallImage] that is expected to cover a small fraction of a watch face
  *   occupied by a single complication. If the smallImage is equal to [SmallImage.PLACEHOLDER] the
  *   renderer must treat it as a placeholder rather than rendering normally, its suggested it should
@@ -1882,8 +1954,10 @@
      * You must at a minimum set the [smallImage] and [contentDescription] fields.
      *
      * @param smallImage The [SmallImage] to be displayed
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications
+     * do not have textual representation this attribute can be used for providing such. Please
+     * do not include the word 'complication' in the description.
      */
     public class Builder(
         private val smallImage: SmallImage,
@@ -1957,6 +2031,14 @@
  * part of the watch face or within a complication. The image is large enough to be cover the entire
  * screen. The image may be cropped to fit the watch face or complication.
  *
+ * A data source that wants to serve a PhotoImageComplicationData must include the following
+ * meta data in its manifest (NB the value is a comma separated list):
+ *
+ * ```
+ * <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
+ *    android:value="LARGE_IMAGE"/>
+ * ```
+ *
  * @property photoImage The [Icon] that is expected to fill a large part of the watch face, large
  *   enough to be shown as either a background or as part of a high resolution complication. This
  *   must not be tinted. If the photoImage is equal to [PhotoImageComplicationData.PLACEHOLDER] the
@@ -1994,8 +2076,10 @@
      * You must at a minimum set the [photoImage] and [contentDescription] fields.
      *
      * @param photoImage The [Icon] to be displayed
-     * @param contentDescription Localized description for use by screen readers. Please do not
-     *   include the word 'complication' in the description.
+     * @param contentDescription Defines localized text that briefly describes content of the
+     * complication. This property is used primarily for accessibility. Since some complications
+     * do not have textual representation this attribute can be used for providing such. Please
+     * do not include the word 'complication' in the description.
      */
     public class Builder(
         private val photoImage: Icon,
diff --git a/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt b/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
index 943df16..57efd34 100644
--- a/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
+++ b/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionGuavaTest.kt
@@ -43,6 +43,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.data.LongTextComplicationData
 import androidx.wear.watchface.complications.rendering.CanvasComplicationDrawable
@@ -80,6 +81,7 @@
             placeholderWatchState,
             mockInvalidateCallback
         )
+    @OptIn(ComplicationExperimental::class)
     private val leftComplication =
         @Suppress("DEPRECATION")
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
@@ -107,6 +109,7 @@
             placeholderWatchState,
             mockInvalidateCallback
         )
+    @OptIn(ComplicationExperimental::class)
     private val rightComplication =
         @Suppress("DEPRECATION")
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
diff --git a/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionTest.kt b/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionTest.kt
index 2942f97..edc3db4 100644
--- a/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionTest.kt
+++ b/wear/watchface/watchface-editor/src/androidTest/java/androidx/wear/watchface/editor/EditorSessionTest.kt
@@ -75,6 +75,7 @@
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
 import androidx.wear.watchface.complications.data.ComplicationData
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationText
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.data.EmptyComplicationData
@@ -197,6 +198,7 @@
         placeholderWatchState,
         mockInvalidateCallback
     )
+@OptIn(ComplicationExperimental::class)
 private val backgroundComplication =
     ComplicationSlot.createBackgroundComplicationSlotBuilder(
             BACKGROUND_COMPLICATION_ID,
@@ -508,6 +510,7 @@
     internal val complicationDeniedDialogIntent = Intent("ComplicationDeniedDialog")
     internal val complicationRationaleDialogIntent = Intent("ComplicationRationaleDialog")
 
+    @OptIn(ComplicationExperimental::class)
     private val leftComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 LEFT_COMPLICATION_ID,
@@ -538,6 +541,7 @@
             )
             .build()
 
+    @OptIn(ComplicationExperimental::class)
     private val rightComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 RIGHT_COMPLICATION_ID,
@@ -547,7 +551,8 @@
                     ComplicationType.LONG_TEXT,
                     ComplicationType.SHORT_TEXT,
                     ComplicationType.MONOCHROMATIC_IMAGE,
-                    ComplicationType.SMALL_IMAGE
+                    ComplicationType.SMALL_IMAGE,
+                    ComplicationType.PHOTO_IMAGE
                 ),
                 DefaultComplicationDataSourcePolicy(
                     ComponentName("com.primary.package", "com.primary.app"),
@@ -887,6 +892,7 @@
         }
     }
 
+    @OptIn(ComplicationExperimental::class)
     @Suppress("DEPRECATION") // Old DefaultComplicationDataSourcePolicy constructor
     @Test
     public fun fixedComplicationDataSource() {
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
index a2c88c1..44f60d4 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasAnalogWatchFaceService.kt
@@ -44,6 +44,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationDeniedActivity
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationRationalActivity
@@ -266,6 +267,7 @@
         complicationSlotsManager: ComplicationSlotsManager
     ) = UserStyleFlavors(listOf(exampleFlavor))
 
+    @OptIn(ComplicationExperimental::class)
     public override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ): ComplicationSlotsManager {
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
index 64b584d..14fc4dd 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasDigitalWatchFaceService.kt
@@ -53,6 +53,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationDeniedActivity
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationRationalActivity
@@ -122,6 +123,7 @@
         )
     }
 
+    @OptIn(ComplicationExperimental::class)
     private val leftComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 ComplicationID.LEFT.ordinal,
@@ -149,6 +151,7 @@
             .setScreenReaderNameResourceId(R.string.left_complication_screen_reader_name)
             .build()
 
+    @OptIn(ComplicationExperimental::class)
     private val rightComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 ComplicationID.RIGHT.ordinal,
@@ -188,6 +191,7 @@
         )
 
     // The upper and lower complicationSlots change shape depending on the complication's type.
+    @OptIn(ComplicationExperimental::class)
     private val upperComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 ComplicationID.UPPER.ordinal,
@@ -218,6 +222,7 @@
             .setScreenReaderNameResourceId(R.string.upper_complication_screen_reader_name)
             .build()
 
+    @OptIn(ComplicationExperimental::class)
     private val lowerComplication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 ComplicationID.LOWER.ordinal,
@@ -248,6 +253,7 @@
             .setScreenReaderNameResourceId(R.string.lower_complication_screen_reader_name)
             .build()
 
+    @OptIn(ComplicationExperimental::class)
     private val backgroundComplication =
         ComplicationSlot.createBackgroundComplicationSlotBuilder(
                 ComplicationID.BACKGROUND.ordinal,
@@ -261,6 +267,7 @@
 
     override fun createUserStyleSchema() = UserStyleSchema(listOf(colorStyleSetting))
 
+    @OptIn(ComplicationExperimental::class)
     override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ) =
@@ -275,6 +282,7 @@
             currentUserStyleRepository
         )
 
+    @OptIn(ComplicationExperimental::class)
     override suspend fun createWatchFace(
         surfaceHolder: SurfaceHolder,
         watchState: WatchState,
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleHierarchicalStyleWatchFaceService.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleHierarchicalStyleWatchFaceService.kt
index 23be167..8820469 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleHierarchicalStyleWatchFaceService.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleHierarchicalStyleWatchFaceService.kt
@@ -39,6 +39,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.rendering.CanvasComplicationDrawable
 import androidx.wear.watchface.style.CurrentUserStyleRepository
@@ -287,6 +288,7 @@
 
     private val watchFaceStyle by lazy { WatchFaceColorStyle.create(this, "red_style") }
 
+    @OptIn(ComplicationExperimental::class)
     public override fun createComplicationSlotsManager(
         currentUserStyleRepository: CurrentUserStyleRepository
     ): ComplicationSlotsManager {
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
index b102b22..14a0b40 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
@@ -38,6 +38,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationDeniedActivity
 import androidx.wear.watchface.complications.permission.dialogs.sample.ComplicationRationalActivity
@@ -94,6 +95,7 @@
         )
     }
 
+    @OptIn(ComplicationExperimental::class)
     private val complication =
         ComplicationSlot.createRoundRectComplicationSlotBuilder(
                 EXAMPLE_OPENGL_COMPLICATION_ID,
diff --git a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
index acb1d98..4eafb07 100644
--- a/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
+++ b/wear/watchface/watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
@@ -35,6 +35,7 @@
 import androidx.wear.watchface.complications.ComplicationSlotBounds
 import androidx.wear.watchface.complications.DefaultComplicationDataSourcePolicy
 import androidx.wear.watchface.complications.SystemDataSources
+import androidx.wear.watchface.complications.data.ComplicationExperimental
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.rendering.CanvasComplicationDrawable
 import androidx.wear.watchface.complications.rendering.ComplicationDrawable
@@ -136,6 +137,7 @@
                 )
             )
 
+        @ComplicationExperimental
         override fun createComplicationSlotsManager(
             currentUserStyleRepository: CurrentUserStyleRepository
         ): ComplicationSlotsManager {
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
index 2ca41ee..0def254 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/ComplicationSlot.kt
@@ -502,6 +502,7 @@
          * @param bounds The complication's [ComplicationSlotBounds].
          */
         @JvmStatic
+        @OptIn(ComplicationExperimental::class)
         public fun createRoundRectComplicationSlotBuilder(
             id: Int,
             canvasComplicationFactory: CanvasComplicationFactory,
@@ -538,6 +539,7 @@
          *   the initial complication data source when the watch is first installed.
          */
         @JvmStatic
+        @OptIn(ComplicationExperimental::class)
         public fun createBackgroundComplicationSlotBuilder(
             id: Int,
             canvasComplicationFactory: CanvasComplicationFactory,
@@ -584,6 +586,7 @@
          */
         // TODO(b/230364881): Deprecate when BoundingArc is no longer experimental.
         @JvmStatic
+        @OptIn(ComplicationExperimental::class)
         public fun createEdgeComplicationSlotBuilder(
             id: Int,
             canvasComplicationFactory: CanvasComplicationFactory,
@@ -623,12 +626,14 @@
         @JvmStatic
         @JvmOverloads
         @ComplicationExperimental
+        @Suppress("UnavailableSymbol")
         public fun createEdgeComplicationSlotBuilder(
             id: Int,
             canvasComplicationFactory: CanvasComplicationFactory,
             supportedTypes: List<ComplicationType>,
             defaultDataSourcePolicy: DefaultComplicationDataSourcePolicy,
             bounds: ComplicationSlotBounds,
+            @Suppress("HiddenTypeParameter")
             boundingArc: BoundingArc,
             complicationTapFilter: ComplicationTapFilter =
                 object : ComplicationTapFilter {
@@ -719,6 +724,10 @@
                 ".systemDataSourceFallbackDefaultType."
         )
         public fun setDefaultDataSourceType(defaultDataSourceType: ComplicationType): Builder {
+            require(defaultDataSourceType in supportedTypes) {
+                "Can't set $defaultDataSourceType because it's not in the supportedTypes list:" +
+                    " $supportedTypes"
+            }
             defaultDataSourcePolicy =
                 when {
                     defaultDataSourcePolicy.secondaryDataSource != null ->
@@ -798,8 +807,33 @@
         }
 
         /** Constructs the [ComplicationSlot]. */
-        public fun build(): ComplicationSlot =
-            ComplicationSlot(
+        public fun build(): ComplicationSlot {
+            require(defaultDataSourcePolicy.primaryDataSourceDefaultType == null ||
+                defaultDataSourcePolicy.primaryDataSourceDefaultType in supportedTypes
+            ) {
+                "defaultDataSourcePolicy.primaryDataSourceDefaultType " +
+                    "${defaultDataSourcePolicy.primaryDataSourceDefaultType} must be in the" +
+                    " supportedTypes list: $supportedTypes"
+            }
+
+            require(defaultDataSourcePolicy.secondaryDataSourceDefaultType == null ||
+                defaultDataSourcePolicy.secondaryDataSourceDefaultType in supportedTypes
+            ) {
+                "defaultDataSourcePolicy.secondaryDataSourceDefaultType " +
+                    "${defaultDataSourcePolicy.secondaryDataSourceDefaultType} must be in the" +
+                    " supportedTypes list: $supportedTypes"
+            }
+
+            require(defaultDataSourcePolicy.systemDataSourceFallbackDefaultType ==
+                ComplicationType.NOT_CONFIGURED ||
+                defaultDataSourcePolicy.systemDataSourceFallbackDefaultType in supportedTypes
+            ) {
+                "defaultDataSourcePolicy.systemDataSourceFallbackDefaultType " +
+                    "${defaultDataSourcePolicy.systemDataSourceFallbackDefaultType} must be in " +
+                    "the supportedTypes list: $supportedTypes"
+            }
+
+            return ComplicationSlot(
                 id,
                 accessibilityTraversalIndex,
                 boundsType,
@@ -816,6 +850,7 @@
                 screenReaderNameResourceId,
                 boundingArc
             )
+        }
     }
 
     internal interface InvalidateListener {
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 97ada96..e7f10f7 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -1079,7 +1079,7 @@
                     { watchState, listener ->
                         CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                     },
-                    emptyList(),
+                    listOf(ComplicationType.SHORT_TEXT),
                     DefaultComplicationDataSourcePolicy(
                         SystemDataSources.DATA_SOURCE_SUNRISE_SUNSET
                     ),
@@ -1094,7 +1094,7 @@
                     { watchState, listener ->
                         CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                     },
-                    emptyList(),
+                    listOf(ComplicationType.SHORT_TEXT),
                     DefaultComplicationDataSourcePolicy(
                         SystemDataSources.DATA_SOURCE_SUNRISE_SUNSET
                     ),
@@ -1109,7 +1109,7 @@
                     { watchState, listener ->
                         CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                     },
-                    emptyList(),
+                    listOf(ComplicationType.SHORT_TEXT),
                     DefaultComplicationDataSourcePolicy(
                         SystemDataSources.DATA_SOURCE_SUNRISE_SUNSET
                     ),
@@ -2146,7 +2146,7 @@
                     { watchState, listener ->
                         CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                     },
-                    emptyList(),
+                    listOf(ComplicationType.SHORT_TEXT),
                     DefaultComplicationDataSourcePolicy(
                         dataSource1,
                         dataSource2,
@@ -2181,7 +2181,7 @@
                     { watchState, listener ->
                         CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                     },
-                    emptyList(),
+                    listOf(ComplicationType.SHORT_TEXT),
                     DefaultComplicationDataSourcePolicy(
                         dataSource1,
                         dataSource2,
diff --git a/wear/wear-remote-interactions/build.gradle b/wear/wear-remote-interactions/build.gradle
index 2396d640..f821579 100644
--- a/wear/wear-remote-interactions/build.gradle
+++ b/wear/wear-remote-interactions/build.gradle
@@ -26,8 +26,8 @@
     api("androidx.annotation:annotation:1.1.0")
     api(libs.kotlinStdlib)
     api(libs.guavaListenableFuture)
-    api(libs.kotlinCoroutinesGuava)
-    implementation("androidx.concurrent:concurrent-futures:1.0.0")
+    api("androidx.concurrent:concurrent-futures-ktx:1.1.0")
+    api(libs.kotlinCoroutinesCore)
 
     androidTestImplementation(libs.testExtJunit)
     androidTestImplementation(libs.testCore)
diff --git a/webkit/webkit/api/1.7.0-beta02.txt b/webkit/webkit/api/1.7.0-beta02.txt
new file mode 100644
index 0000000..f1058a2
--- /dev/null
+++ b/webkit/webkit/api/1.7.0-beta02.txt
@@ -0,0 +1,312 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+  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![]?);
+  }
+
+  public abstract class JavaScriptReplyProxy {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+  }
+
+  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);
+  }
+
+  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(String);
+    method public androidx.webkit.ProxyConfig.Builder addDirect();
+    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();
+  }
+
+  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 abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  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?);
+  }
+
+  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!>);
+  }
+
+  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);
+  }
+
+  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 class WebMessageCompat {
+    ctor public WebMessageCompat(String?);
+    ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+    method public String? getData();
+    method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+  }
+
+  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(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(android.os.Handler?, 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.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 @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.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);
+    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
+  }
+
+  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(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+    method @RequiresApi(27) 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.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+    method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @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") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+    method @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") 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") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @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 @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") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+    method @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!>?);
+  }
+
+  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);
+  }
+
+  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 CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+    field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+    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 OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+    field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+    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 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 VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+    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";
+  }
+
+  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?);
+  }
+
+}
+
diff --git a/webkit/webkit/api/public_plus_experimental_1.7.0-beta02.txt b/webkit/webkit/api/public_plus_experimental_1.7.0-beta02.txt
new file mode 100644
index 0000000..f1058a2
--- /dev/null
+++ b/webkit/webkit/api/public_plus_experimental_1.7.0-beta02.txt
@@ -0,0 +1,312 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+  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![]?);
+  }
+
+  public abstract class JavaScriptReplyProxy {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+  }
+
+  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);
+  }
+
+  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(String);
+    method public androidx.webkit.ProxyConfig.Builder addDirect();
+    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();
+  }
+
+  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 abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  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?);
+  }
+
+  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!>);
+  }
+
+  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);
+  }
+
+  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 class WebMessageCompat {
+    ctor public WebMessageCompat(String?);
+    ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+    method public String? getData();
+    method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+  }
+
+  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(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(android.os.Handler?, 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.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 @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.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);
+    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
+  }
+
+  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(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+    method @RequiresApi(27) 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.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+    method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @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") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+    method @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") 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") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @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 @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") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+    method @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!>?);
+  }
+
+  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);
+  }
+
+  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 CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+    field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+    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 OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+    field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+    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 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 VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+    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";
+  }
+
+  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?);
+  }
+
+}
+
diff --git a/webkit/webkit/api/res-1.7.0-beta02.txt b/webkit/webkit/api/res-1.7.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webkit/webkit/api/res-1.7.0-beta02.txt
diff --git a/webkit/webkit/api/restricted_1.7.0-beta02.txt b/webkit/webkit/api/restricted_1.7.0-beta02.txt
new file mode 100644
index 0000000..f1058a2
--- /dev/null
+++ b/webkit/webkit/api/restricted_1.7.0-beta02.txt
@@ -0,0 +1,312 @@
+// Signature format: 4.0
+package androidx.webkit {
+
+  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![]?);
+  }
+
+  public abstract class JavaScriptReplyProxy {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public abstract void postMessage(String);
+  }
+
+  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);
+  }
+
+  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(String);
+    method public androidx.webkit.ProxyConfig.Builder addDirect();
+    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();
+  }
+
+  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 abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method @WorkerThread public abstract android.webkit.WebResourceResponse? shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  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?);
+  }
+
+  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!>);
+  }
+
+  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);
+  }
+
+  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 class WebMessageCompat {
+    ctor public WebMessageCompat(String?);
+    ctor public WebMessageCompat(String?, androidx.webkit.WebMessagePortCompat![]?);
+    method public String? getData();
+    method public androidx.webkit.WebMessagePortCompat![]? getPorts();
+  }
+
+  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(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(android.os.Handler?, 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.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 @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.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);
+    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
+  }
+
+  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(23) public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+    method @RequiresApi(21) @UiThread public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+    method @RequiresApi(27) 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.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
+    method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @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") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebViewClient getWebViewClient(android.webkit.WebView);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_VIEW_RENDERER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") 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") public static androidx.webkit.WebViewRenderProcessClient? getWebViewRenderProcessClient(android.webkit.WebView);
+    method @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") 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") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @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 @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") public static void setWebViewRenderProcessClient(android.webkit.WebView, java.util.concurrent.Executor, androidx.webkit.WebViewRenderProcessClient);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
+    method @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!>?);
+  }
+
+  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);
+  }
+
+  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 CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
+    field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+    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 OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+    field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
+    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 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 VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+    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";
+  }
+
+  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?);
+  }
+
+}
+
diff --git a/window/extensions/core/core/api/1.0.0-beta03.txt b/window/extensions/core/core/api/1.0.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/window/extensions/core/core/api/1.0.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/window/extensions/core/core/api/current.ignore b/window/extensions/core/core/api/current.ignore
deleted file mode 100644
index e18e594..0000000
--- a/window/extensions/core/core/api/current.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-RemovedPackage: androidx.window.extensions.core.util.function:
-    Removed package androidx.window.extensions.core.util.function
diff --git a/window/extensions/core/core/api/public_plus_experimental_1.0.0-beta03.txt b/window/extensions/core/core/api/public_plus_experimental_1.0.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/window/extensions/core/core/api/public_plus_experimental_1.0.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/window/extensions/core/core/api/res-1.0.0-beta03.txt b/window/extensions/core/core/api/res-1.0.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/extensions/core/core/api/res-1.0.0-beta03.txt
diff --git a/window/extensions/core/core/api/restricted_1.0.0-beta03.txt b/window/extensions/core/core/api/restricted_1.0.0-beta03.txt
new file mode 100644
index 0000000..1763913
--- /dev/null
+++ b/window/extensions/core/core/api/restricted_1.0.0-beta03.txt
@@ -0,0 +1,17 @@
+// Signature format: 4.0
+package androidx.window.extensions.core.util.function {
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.FunctionalInterface public interface Consumer<T> {
+    method public void accept(T!);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.FunctionalInterface public interface Function<T, R> {
+    method public R! apply(T!);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.FunctionalInterface public interface Predicate<T> {
+    method public boolean test(T!);
+  }
+
+}
+
diff --git a/window/window-core/api/1.1.0-beta03.txt b/window/window-core/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..624b2df
--- /dev/null
+++ b/window/window-core/api/1.1.0-beta03.txt
@@ -0,0 +1,38 @@
+// Signature format: 4.0
+package androidx.window.core.layout {
+
+  public final class WindowHeightSizeClass {
+    field public static final androidx.window.core.layout.WindowHeightSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass MEDIUM;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+  }
+
+  public final class WindowSizeClass {
+    method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+    method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
+    method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
+    property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
+    property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
+    field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+    method public androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+  }
+
+  public final class WindowWidthSizeClass {
+    field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass MEDIUM;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+  }
+
+}
+
diff --git a/window/window-core/api/public_plus_experimental_1.1.0-beta03.txt b/window/window-core/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..624b2df
--- /dev/null
+++ b/window/window-core/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,38 @@
+// Signature format: 4.0
+package androidx.window.core.layout {
+
+  public final class WindowHeightSizeClass {
+    field public static final androidx.window.core.layout.WindowHeightSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass MEDIUM;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+  }
+
+  public final class WindowSizeClass {
+    method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+    method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
+    method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
+    property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
+    property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
+    field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+    method public androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+  }
+
+  public final class WindowWidthSizeClass {
+    field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass MEDIUM;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+  }
+
+}
+
diff --git a/window/window-core/api/res-1.1.0-beta03.txt b/window/window-core/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-core/api/res-1.1.0-beta03.txt
diff --git a/window/window-core/api/restricted_1.1.0-beta03.txt b/window/window-core/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..624b2df
--- /dev/null
+++ b/window/window-core/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,38 @@
+// Signature format: 4.0
+package androidx.window.core.layout {
+
+  public final class WindowHeightSizeClass {
+    field public static final androidx.window.core.layout.WindowHeightSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowHeightSizeClass MEDIUM;
+  }
+
+  public static final class WindowHeightSizeClass.Companion {
+  }
+
+  public final class WindowSizeClass {
+    method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+    method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
+    method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
+    property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
+    property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
+    field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
+  }
+
+  public static final class WindowSizeClass.Companion {
+    method public androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+  }
+
+  public final class WindowWidthSizeClass {
+    field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass EXPANDED;
+    field public static final androidx.window.core.layout.WindowWidthSizeClass MEDIUM;
+  }
+
+  public static final class WindowWidthSizeClass.Companion {
+  }
+
+}
+
diff --git a/window/window-demos/demo/build.gradle b/window/window-demos/demo/build.gradle
index 49f7d60..65adb00 100644
--- a/window/window-demos/demo/build.gradle
+++ b/window/window-demos/demo/build.gradle
@@ -52,6 +52,8 @@
     implementation("androidx.core:core-ktx:1.3.2")
     implementation("androidx.activity:activity:1.2.0")
     implementation("androidx.recyclerview:recyclerview:1.2.1")
+    // TODO(b/262583150): force tracing 1.1.0 since its required by androidTest
+    implementation("androidx.tracing:tracing:1.1.0")
     api(libs.constraintLayout)
     // TODO(b/152245564) Conflicting dependencies cause IDE errors.
     implementation("androidx.lifecycle:lifecycle-viewmodel:2.4.0-alpha02")
diff --git a/window/window-java/api/1.1.0-beta03.txt b/window/window-java/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..39c35ac
--- /dev/null
+++ b/window/window-java/api/1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.java.layout {
+
+  public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
+    ctor public WindowInfoTrackerCallbackAdapter(androidx.window.layout.WindowInfoTracker tracker);
+    method public void addWindowLayoutInfoListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void addWindowLayoutInfoListener(@UiContext android.content.Context context, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+  }
+
+}
+
diff --git a/window/window-java/api/public_plus_experimental_1.1.0-beta03.txt b/window/window-java/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..d621966
--- /dev/null
+++ b/window/window-java/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.window.java.embedding {
+
+  @androidx.window.core.ExperimentalWindowApi public final class SplitControllerCallbackAdapter {
+    ctor public SplitControllerCallbackAdapter(androidx.window.embedding.SplitController controller);
+    method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+    method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+  }
+
+}
+
+package androidx.window.java.layout {
+
+  public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
+    ctor public WindowInfoTrackerCallbackAdapter(androidx.window.layout.WindowInfoTracker tracker);
+    method public void addWindowLayoutInfoListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void addWindowLayoutInfoListener(@UiContext android.content.Context context, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+  }
+
+}
+
diff --git a/window/window-java/api/res-1.1.0-beta03.txt b/window/window-java/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-java/api/res-1.1.0-beta03.txt
diff --git a/window/window-java/api/restricted_1.1.0-beta03.txt b/window/window-java/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..39c35ac
--- /dev/null
+++ b/window/window-java/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.java.layout {
+
+  public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
+    ctor public WindowInfoTrackerCallbackAdapter(androidx.window.layout.WindowInfoTracker tracker);
+    method public void addWindowLayoutInfoListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void addWindowLayoutInfoListener(@UiContext android.content.Context context, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+    method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+  }
+
+}
+
diff --git a/window/window-rxjava2/api/1.1.0-beta03.txt b/window/window-rxjava2/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..5250696
--- /dev/null
+++ b/window/window-rxjava2/api/1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-rxjava2/api/public_plus_experimental_1.1.0-beta03.txt b/window/window-rxjava2/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..5250696
--- /dev/null
+++ b/window/window-rxjava2/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-rxjava2/api/res-1.1.0-beta03.txt b/window/window-rxjava2/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-rxjava2/api/res-1.1.0-beta03.txt
diff --git a/window/window-rxjava2/api/restricted_1.1.0-beta03.txt b/window/window-rxjava2/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..5250696
--- /dev/null
+++ b/window/window-rxjava2/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-rxjava3/api/1.1.0-beta03.txt b/window/window-rxjava3/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..23510cc
--- /dev/null
+++ b/window/window-rxjava3/api/1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-rxjava3/api/public_plus_experimental_1.1.0-beta03.txt b/window/window-rxjava3/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..23510cc
--- /dev/null
+++ b/window/window-rxjava3/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-rxjava3/api/res-1.1.0-beta03.txt b/window/window-rxjava3/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-rxjava3/api/res-1.1.0-beta03.txt
diff --git a/window/window-rxjava3/api/restricted_1.1.0-beta03.txt b/window/window-rxjava3/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..23510cc
--- /dev/null
+++ b/window/window-rxjava3/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+  public final class WindowInfoTrackerRx {
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+    method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+  }
+
+}
+
diff --git a/window/window-testing/api/1.1.0-beta03.txt b/window/window-testing/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..12a7d20
--- /dev/null
+++ b/window/window-testing/api/1.1.0-beta03.txt
@@ -0,0 +1,24 @@
+// Signature format: 4.0
+package androidx.window.testing.layout {
+
+  public final class DisplayFeatureTesting {
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+  }
+
+  public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+    ctor public WindowLayoutInfoPublisherRule();
+    method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+    method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+  }
+
+  public final class WindowLayoutInfoTesting {
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo(optional java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo();
+  }
+
+}
+
diff --git a/window/window-testing/api/public_plus_experimental_1.1.0-beta03.txt b/window/window-testing/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..16174f8
--- /dev/null
+++ b/window/window-testing/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,68 @@
+// Signature format: 4.0
+package androidx.window.testing.embedding {
+
+  @androidx.window.core.ExperimentalWindowApi public final class ActivityEmbeddingTestRule implements org.junit.rules.TestRule {
+    ctor public ActivityEmbeddingTestRule();
+    method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+    method public void overrideIsActivityEmbedded(android.app.Activity activity, boolean isActivityEmbedded);
+    method public void overrideSplitInfo(android.app.Activity activity, java.util.List<androidx.window.embedding.SplitInfo> splitInfoList);
+    method public void overrideSplitSupportStatus(androidx.window.embedding.SplitController.SplitSupportStatus status);
+  }
+
+  public final class TestActivityStack {
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess, optional boolean isEmpty);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.ActivityStack createTestActivityStack();
+  }
+
+  public final class TestSplitAttributesCalculatorParams {
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied, optional String? splitRuleTag);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics);
+  }
+
+  public final class TestSplitInfo {
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack, optional androidx.window.embedding.SplitAttributes splitAttributes);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.embedding.SplitInfo createTestSplitInfo();
+  }
+
+}
+
+package androidx.window.testing.layout {
+
+  public final class DisplayFeatureTesting {
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional int center, optional int size);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional int center);
+    method @androidx.window.core.ExperimentalWindowApi public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds);
+  }
+
+  @androidx.window.core.ExperimentalWindowApi public final class StubWindowMetricsCalculatorRule implements org.junit.rules.TestRule {
+    ctor public StubWindowMetricsCalculatorRule();
+    method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+  }
+
+  public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+    ctor public WindowLayoutInfoPublisherRule();
+    method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+    method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+  }
+
+  public final class WindowLayoutInfoTesting {
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo(optional java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo();
+  }
+
+}
+
diff --git a/window/window-testing/api/res-1.1.0-beta03.txt b/window/window-testing/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-testing/api/res-1.1.0-beta03.txt
diff --git a/window/window-testing/api/restricted_1.1.0-beta03.txt b/window/window-testing/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..12a7d20
--- /dev/null
+++ b/window/window-testing/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,24 @@
+// Signature format: 4.0
+package androidx.window.testing.layout {
+
+  public final class DisplayFeatureTesting {
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+    method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+  }
+
+  public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+    ctor public WindowLayoutInfoPublisherRule();
+    method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+    method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+  }
+
+  public final class WindowLayoutInfoTesting {
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo(optional java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+    method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo();
+  }
+
+}
+
diff --git a/window/window/api/1.1.0-beta03.txt b/window/window/api/1.1.0-beta03.txt
new file mode 100644
index 0000000..5617dbb
--- /dev/null
+++ b/window/window/api/1.1.0-beta03.txt
@@ -0,0 +1,337 @@
+// Signature format: 4.0
+package androidx.window {
+
+  public final class WindowProperties {
+    field public static final androidx.window.WindowProperties INSTANCE;
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+  }
+
+}
+
+package androidx.window.embedding {
+
+  public final class ActivityEmbeddingController {
+    method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+    method public boolean isActivityEmbedded(android.app.Activity activity);
+    field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
+  }
+
+  public static final class ActivityEmbeddingController.Companion {
+    method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+  }
+
+  public final class ActivityFilter {
+    ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
+    method public android.content.ComponentName getComponentName();
+    method public String? getIntentAction();
+    method public boolean matchesActivity(android.app.Activity activity);
+    method public boolean matchesIntent(android.content.Intent intent);
+    property public final android.content.ComponentName componentName;
+    property public final String? intentAction;
+  }
+
+  public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
+    method public boolean getAlwaysExpand();
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    property public final boolean alwaysExpand;
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+  }
+
+  public static final class ActivityRule.Builder {
+    ctor public ActivityRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters);
+    method public androidx.window.embedding.ActivityRule build();
+    method public androidx.window.embedding.ActivityRule.Builder setAlwaysExpand(boolean alwaysExpand);
+    method public androidx.window.embedding.ActivityRule.Builder setTag(String? tag);
+  }
+
+  public final class ActivityStack {
+    method public operator boolean contains(android.app.Activity activity);
+    method public boolean isEmpty();
+    property public final boolean isEmpty;
+  }
+
+  public final class EmbeddingAspectRatio {
+    method public static androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_ALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_DISALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio.Companion Companion;
+  }
+
+  public static final class EmbeddingAspectRatio.Companion {
+    method public androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+  }
+
+  public abstract class EmbeddingRule {
+    method public final String? getTag();
+    property public final String? tag;
+  }
+
+  public final class RuleController {
+    method public void addRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void clearRules();
+    method public static androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> getRules();
+    method public static java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+    method public void removeRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void setRules(java.util.Set<? extends androidx.window.embedding.EmbeddingRule> rules);
+    field public static final androidx.window.embedding.RuleController.Companion Companion;
+  }
+
+  public static final class RuleController.Companion {
+    method public androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+  }
+
+  public final class SplitAttributes {
+    method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
+    method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
+    property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
+    property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
+    field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
+  }
+
+  public static final class SplitAttributes.Builder {
+    ctor public SplitAttributes.Builder();
+    method public androidx.window.embedding.SplitAttributes build();
+    method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
+    method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
+  }
+
+  public static final class SplitAttributes.Companion {
+  }
+
+  public static final class SplitAttributes.LayoutDirection {
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection BOTTOM_TO_TOP;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LEFT_TO_RIGHT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LOCALE;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection RIGHT_TO_LEFT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection TOP_TO_BOTTOM;
+  }
+
+  public static final class SplitAttributes.LayoutDirection.Companion {
+  }
+
+  public static final class SplitAttributes.SplitType {
+    method public static androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+    field public static final androidx.window.embedding.SplitAttributes.SplitType.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EQUAL;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EXPAND;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_HINGE;
+  }
+
+  public static final class SplitAttributes.SplitType.Companion {
+    method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+  }
+
+  public final class SplitController {
+    method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+    method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
+    method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+    property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
+    field public static final androidx.window.embedding.SplitController.Companion Companion;
+  }
+
+  public static final class SplitController.Companion {
+    method public androidx.window.embedding.SplitController getInstance(android.content.Context context);
+  }
+
+  public static final class SplitController.SplitSupportStatus {
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus.Companion Companion;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_AVAILABLE;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_ERROR_PROPERTY_NOT_DECLARED;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_UNAVAILABLE;
+  }
+
+  public static final class SplitController.SplitSupportStatus.Companion {
+  }
+
+  public final class SplitInfo {
+    method public operator boolean contains(android.app.Activity activity);
+    method public androidx.window.embedding.ActivityStack getPrimaryActivityStack();
+    method public androidx.window.embedding.ActivityStack getSecondaryActivityStack();
+    method public androidx.window.embedding.SplitAttributes getSplitAttributes();
+    property public final androidx.window.embedding.ActivityStack primaryActivityStack;
+    property public final androidx.window.embedding.ActivityStack secondaryActivityStack;
+    property public final androidx.window.embedding.SplitAttributes splitAttributes;
+  }
+
+  public final class SplitPairFilter {
+    ctor public SplitPairFilter(android.content.ComponentName primaryActivityName, android.content.ComponentName secondaryActivityName, String? secondaryActivityIntentAction);
+    method public android.content.ComponentName getPrimaryActivityName();
+    method public String? getSecondaryActivityIntentAction();
+    method public android.content.ComponentName getSecondaryActivityName();
+    method public boolean matchesActivityIntentPair(android.app.Activity primaryActivity, android.content.Intent secondaryActivityIntent);
+    method public boolean matchesActivityPair(android.app.Activity primaryActivity, android.app.Activity secondaryActivity);
+    property public final android.content.ComponentName primaryActivityName;
+    property public final String? secondaryActivityIntentAction;
+    property public final android.content.ComponentName secondaryActivityName;
+  }
+
+  public final class SplitPairRule extends androidx.window.embedding.SplitRule {
+    method public boolean getClearTop();
+    method public java.util.Set<androidx.window.embedding.SplitPairFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithSecondary();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishSecondaryWithPrimary();
+    property public final boolean clearTop;
+    property public final java.util.Set<androidx.window.embedding.SplitPairFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary;
+  }
+
+  public static final class SplitPairRule.Builder {
+    ctor public SplitPairRule.Builder(java.util.Set<androidx.window.embedding.SplitPairFilter> filters);
+    method public androidx.window.embedding.SplitPairRule build();
+    method public androidx.window.embedding.SplitPairRule.Builder setClearTop(boolean clearTop);
+    method public androidx.window.embedding.SplitPairRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishPrimaryWithSecondary(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishSecondaryWithPrimary(androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setTag(String? tag);
+  }
+
+  public final class SplitPlaceholderRule extends androidx.window.embedding.SplitRule {
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithPlaceholder();
+    method public android.content.Intent getPlaceholderIntent();
+    method public boolean isSticky();
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder;
+    property public final boolean isSticky;
+    property public final android.content.Intent placeholderIntent;
+  }
+
+  public static final class SplitPlaceholderRule.Builder {
+    ctor public SplitPlaceholderRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters, android.content.Intent placeholderIntent);
+    method public androidx.window.embedding.SplitPlaceholderRule build();
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setFinishPrimaryWithPlaceholder(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setSticky(boolean isSticky);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setTag(String? tag);
+  }
+
+  public class SplitRule extends androidx.window.embedding.EmbeddingRule {
+    method public final androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInLandscape();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInPortrait();
+    method public final int getMinHeightDp();
+    method public final int getMinSmallestWidthDp();
+    method public final int getMinWidthDp();
+    property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInLandscape;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInPortrait;
+    property public final int minHeightDp;
+    property public final int minSmallestWidthDp;
+    property public final int minWidthDp;
+    field public static final androidx.window.embedding.SplitRule.Companion Companion;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT;
+    field public static final int SPLIT_MIN_DIMENSION_ALWAYS_ALLOW = 0; // 0x0
+    field public static final int SPLIT_MIN_DIMENSION_DP_DEFAULT = 600; // 0x258
+  }
+
+  public static final class SplitRule.Companion {
+  }
+
+  public static final class SplitRule.FinishBehavior {
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ADJACENT;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ALWAYS;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior.Companion Companion;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior NEVER;
+  }
+
+  public static final class SplitRule.FinishBehavior.Companion {
+  }
+
+}
+
+package androidx.window.layout {
+
+  public interface DisplayFeature {
+    method public android.graphics.Rect getBounds();
+    property public abstract android.graphics.Rect bounds;
+  }
+
+  public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+    method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.layout.FoldingFeature.State getState();
+    method public boolean isSeparating();
+    property public abstract boolean isSeparating;
+    property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+    property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+    property public abstract androidx.window.layout.FoldingFeature.State state;
+  }
+
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.State FLAT;
+    field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public interface WindowInfoTracker {
+    method public default static androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+    method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(android.app.Activity activity);
+    field public static final androidx.window.layout.WindowInfoTracker.Companion Companion;
+  }
+
+  public static final class WindowInfoTracker.Companion {
+    method public androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+  }
+
+  public final class WindowLayoutInfo {
+    method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+    property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+  }
+
+  public final class WindowMetrics {
+    method public android.graphics.Rect getBounds();
+    property public final android.graphics.Rect bounds;
+  }
+
+  public interface WindowMetricsCalculator {
+    method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(@UiContext android.content.Context context);
+    method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(@UiContext android.content.Context context);
+    method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+    field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+  }
+
+  public static final class WindowMetricsCalculator.Companion {
+    method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+  }
+
+}
+
diff --git a/window/window/api/public_plus_experimental_1.1.0-beta03.txt b/window/window/api/public_plus_experimental_1.1.0-beta03.txt
new file mode 100644
index 0000000..0ac0175
--- /dev/null
+++ b/window/window/api/public_plus_experimental_1.1.0-beta03.txt
@@ -0,0 +1,367 @@
+// Signature format: 4.0
+package androidx.window {
+
+  public final class WindowProperties {
+    field public static final androidx.window.WindowProperties INSTANCE;
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+  }
+
+}
+
+package androidx.window.core {
+
+  @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWindowApi {
+  }
+
+}
+
+package androidx.window.embedding {
+
+  public final class ActivityEmbeddingController {
+    method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+    method public boolean isActivityEmbedded(android.app.Activity activity);
+    field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
+  }
+
+  public static final class ActivityEmbeddingController.Companion {
+    method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+  }
+
+  public final class ActivityFilter {
+    ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
+    method public android.content.ComponentName getComponentName();
+    method public String? getIntentAction();
+    method public boolean matchesActivity(android.app.Activity activity);
+    method public boolean matchesIntent(android.content.Intent intent);
+    property public final android.content.ComponentName componentName;
+    property public final String? intentAction;
+  }
+
+  public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
+    method public boolean getAlwaysExpand();
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    property public final boolean alwaysExpand;
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+  }
+
+  public static final class ActivityRule.Builder {
+    ctor public ActivityRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters);
+    method public androidx.window.embedding.ActivityRule build();
+    method public androidx.window.embedding.ActivityRule.Builder setAlwaysExpand(boolean alwaysExpand);
+    method public androidx.window.embedding.ActivityRule.Builder setTag(String? tag);
+  }
+
+  public final class ActivityStack {
+    method public operator boolean contains(android.app.Activity activity);
+    method public boolean isEmpty();
+    property public final boolean isEmpty;
+  }
+
+  public final class EmbeddingAspectRatio {
+    method public static androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_ALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_DISALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio.Companion Companion;
+  }
+
+  public static final class EmbeddingAspectRatio.Companion {
+    method public androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+  }
+
+  public abstract class EmbeddingRule {
+    method public final String? getTag();
+    property public final String? tag;
+  }
+
+  public final class RuleController {
+    method public void addRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void clearRules();
+    method public static androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> getRules();
+    method public static java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+    method public void removeRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void setRules(java.util.Set<? extends androidx.window.embedding.EmbeddingRule> rules);
+    field public static final androidx.window.embedding.RuleController.Companion Companion;
+  }
+
+  public static final class RuleController.Companion {
+    method public androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+  }
+
+  public final class SplitAttributes {
+    method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
+    method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
+    property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
+    property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
+    field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
+  }
+
+  public static final class SplitAttributes.Builder {
+    ctor public SplitAttributes.Builder();
+    method public androidx.window.embedding.SplitAttributes build();
+    method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
+    method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
+  }
+
+  public static final class SplitAttributes.Companion {
+  }
+
+  public static final class SplitAttributes.LayoutDirection {
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection BOTTOM_TO_TOP;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LEFT_TO_RIGHT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LOCALE;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection RIGHT_TO_LEFT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection TOP_TO_BOTTOM;
+  }
+
+  public static final class SplitAttributes.LayoutDirection.Companion {
+  }
+
+  public static final class SplitAttributes.SplitType {
+    method public static androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+    field public static final androidx.window.embedding.SplitAttributes.SplitType.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EQUAL;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EXPAND;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_HINGE;
+  }
+
+  public static final class SplitAttributes.SplitType.Companion {
+    method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+  }
+
+  @androidx.window.core.ExperimentalWindowApi public final class SplitAttributesCalculatorParams {
+    method public boolean getAreDefaultConstraintsSatisfied();
+    method public androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+    method public android.content.res.Configuration getParentConfiguration();
+    method public androidx.window.layout.WindowLayoutInfo getParentWindowLayoutInfo();
+    method public androidx.window.layout.WindowMetrics getParentWindowMetrics();
+    method public String? getSplitRuleTag();
+    property public final boolean areDefaultConstraintsSatisfied;
+    property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+    property public final android.content.res.Configuration parentConfiguration;
+    property public final androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo;
+    property public final androidx.window.layout.WindowMetrics parentWindowMetrics;
+    property public final String? splitRuleTag;
+  }
+
+  public final class SplitController {
+    method @Deprecated @androidx.window.core.ExperimentalWindowApi public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+    method @androidx.window.core.ExperimentalWindowApi public void clearSplitAttributesCalculator();
+    method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+    method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
+    method @androidx.window.core.ExperimentalWindowApi public boolean isSplitAttributesCalculatorSupported();
+    method @Deprecated @androidx.window.core.ExperimentalWindowApi public boolean isSplitSupported();
+    method @Deprecated @androidx.window.core.ExperimentalWindowApi public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+    method @androidx.window.core.ExperimentalWindowApi public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+    property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
+    field public static final androidx.window.embedding.SplitController.Companion Companion;
+  }
+
+  public static final class SplitController.Companion {
+    method public androidx.window.embedding.SplitController getInstance(android.content.Context context);
+  }
+
+  public static final class SplitController.SplitSupportStatus {
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus.Companion Companion;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_AVAILABLE;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_ERROR_PROPERTY_NOT_DECLARED;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_UNAVAILABLE;
+  }
+
+  public static final class SplitController.SplitSupportStatus.Companion {
+  }
+
+  public final class SplitInfo {
+    method public operator boolean contains(android.app.Activity activity);
+    method public androidx.window.embedding.ActivityStack getPrimaryActivityStack();
+    method public androidx.window.embedding.ActivityStack getSecondaryActivityStack();
+    method public androidx.window.embedding.SplitAttributes getSplitAttributes();
+    property public final androidx.window.embedding.ActivityStack primaryActivityStack;
+    property public final androidx.window.embedding.ActivityStack secondaryActivityStack;
+    property public final androidx.window.embedding.SplitAttributes splitAttributes;
+  }
+
+  public final class SplitPairFilter {
+    ctor public SplitPairFilter(android.content.ComponentName primaryActivityName, android.content.ComponentName secondaryActivityName, String? secondaryActivityIntentAction);
+    method public android.content.ComponentName getPrimaryActivityName();
+    method public String? getSecondaryActivityIntentAction();
+    method public android.content.ComponentName getSecondaryActivityName();
+    method public boolean matchesActivityIntentPair(android.app.Activity primaryActivity, android.content.Intent secondaryActivityIntent);
+    method public boolean matchesActivityPair(android.app.Activity primaryActivity, android.app.Activity secondaryActivity);
+    property public final android.content.ComponentName primaryActivityName;
+    property public final String? secondaryActivityIntentAction;
+    property public final android.content.ComponentName secondaryActivityName;
+  }
+
+  public final class SplitPairRule extends androidx.window.embedding.SplitRule {
+    method public boolean getClearTop();
+    method public java.util.Set<androidx.window.embedding.SplitPairFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithSecondary();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishSecondaryWithPrimary();
+    property public final boolean clearTop;
+    property public final java.util.Set<androidx.window.embedding.SplitPairFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary;
+  }
+
+  public static final class SplitPairRule.Builder {
+    ctor public SplitPairRule.Builder(java.util.Set<androidx.window.embedding.SplitPairFilter> filters);
+    method public androidx.window.embedding.SplitPairRule build();
+    method public androidx.window.embedding.SplitPairRule.Builder setClearTop(boolean clearTop);
+    method public androidx.window.embedding.SplitPairRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishPrimaryWithSecondary(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishSecondaryWithPrimary(androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setTag(String? tag);
+  }
+
+  public final class SplitPlaceholderRule extends androidx.window.embedding.SplitRule {
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithPlaceholder();
+    method public android.content.Intent getPlaceholderIntent();
+    method public boolean isSticky();
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder;
+    property public final boolean isSticky;
+    property public final android.content.Intent placeholderIntent;
+  }
+
+  public static final class SplitPlaceholderRule.Builder {
+    ctor public SplitPlaceholderRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters, android.content.Intent placeholderIntent);
+    method public androidx.window.embedding.SplitPlaceholderRule build();
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setFinishPrimaryWithPlaceholder(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setSticky(boolean isSticky);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setTag(String? tag);
+  }
+
+  public class SplitRule extends androidx.window.embedding.EmbeddingRule {
+    method public final androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInLandscape();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInPortrait();
+    method public final int getMinHeightDp();
+    method public final int getMinSmallestWidthDp();
+    method public final int getMinWidthDp();
+    property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInLandscape;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInPortrait;
+    property public final int minHeightDp;
+    property public final int minSmallestWidthDp;
+    property public final int minWidthDp;
+    field public static final androidx.window.embedding.SplitRule.Companion Companion;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT;
+    field public static final int SPLIT_MIN_DIMENSION_ALWAYS_ALLOW = 0; // 0x0
+    field public static final int SPLIT_MIN_DIMENSION_DP_DEFAULT = 600; // 0x258
+  }
+
+  public static final class SplitRule.Companion {
+  }
+
+  public static final class SplitRule.FinishBehavior {
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ADJACENT;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ALWAYS;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior.Companion Companion;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior NEVER;
+  }
+
+  public static final class SplitRule.FinishBehavior.Companion {
+  }
+
+}
+
+package androidx.window.layout {
+
+  public interface DisplayFeature {
+    method public android.graphics.Rect getBounds();
+    property public abstract android.graphics.Rect bounds;
+  }
+
+  public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+    method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.layout.FoldingFeature.State getState();
+    method public boolean isSeparating();
+    property public abstract boolean isSeparating;
+    property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+    property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+    property public abstract androidx.window.layout.FoldingFeature.State state;
+  }
+
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.State FLAT;
+    field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public interface WindowInfoTracker {
+    method public default static androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+    method @androidx.window.core.ExperimentalWindowApi public default kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(@UiContext android.content.Context context);
+    method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(android.app.Activity activity);
+    field public static final androidx.window.layout.WindowInfoTracker.Companion Companion;
+  }
+
+  public static final class WindowInfoTracker.Companion {
+    method public androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+  }
+
+  public final class WindowLayoutInfo {
+    method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+    property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+  }
+
+  public final class WindowMetrics {
+    method public android.graphics.Rect getBounds();
+    method @RequiresApi(android.os.Build.VERSION_CODES.R) @androidx.window.core.ExperimentalWindowApi public androidx.core.view.WindowInsetsCompat getWindowInsets();
+    property public final android.graphics.Rect bounds;
+  }
+
+  public interface WindowMetricsCalculator {
+    method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(@UiContext android.content.Context context);
+    method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(@UiContext android.content.Context context);
+    method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+    field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+  }
+
+  public static final class WindowMetricsCalculator.Companion {
+    method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+  }
+
+}
+
diff --git a/window/window/api/res-1.1.0-beta03.txt b/window/window/api/res-1.1.0-beta03.txt
new file mode 100644
index 0000000..185352b
--- /dev/null
+++ b/window/window/api/res-1.1.0-beta03.txt
@@ -0,0 +1,21 @@
+attr activityAction
+attr activityName
+attr alwaysExpand
+attr animationBackgroundColor
+attr clearTop
+attr finishPrimaryWithPlaceholder
+attr finishPrimaryWithSecondary
+attr finishSecondaryWithPrimary
+attr placeholderActivityName
+attr primaryActivityName
+attr secondaryActivityAction
+attr secondaryActivityName
+attr splitLayoutDirection
+attr splitMaxAspectRatioInLandscape
+attr splitMaxAspectRatioInPortrait
+attr splitMinHeightDp
+attr splitMinSmallestWidthDp
+attr splitMinWidthDp
+attr splitRatio
+attr stickyPlaceholder
+attr tag
diff --git a/window/window/api/restricted_1.1.0-beta03.txt b/window/window/api/restricted_1.1.0-beta03.txt
new file mode 100644
index 0000000..5617dbb
--- /dev/null
+++ b/window/window/api/restricted_1.1.0-beta03.txt
@@ -0,0 +1,337 @@
+// Signature format: 4.0
+package androidx.window {
+
+  public final class WindowProperties {
+    field public static final androidx.window.WindowProperties INSTANCE;
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
+    field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+  }
+
+}
+
+package androidx.window.embedding {
+
+  public final class ActivityEmbeddingController {
+    method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+    method public boolean isActivityEmbedded(android.app.Activity activity);
+    field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
+  }
+
+  public static final class ActivityEmbeddingController.Companion {
+    method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+  }
+
+  public final class ActivityFilter {
+    ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
+    method public android.content.ComponentName getComponentName();
+    method public String? getIntentAction();
+    method public boolean matchesActivity(android.app.Activity activity);
+    method public boolean matchesIntent(android.content.Intent intent);
+    property public final android.content.ComponentName componentName;
+    property public final String? intentAction;
+  }
+
+  public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
+    method public boolean getAlwaysExpand();
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    property public final boolean alwaysExpand;
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+  }
+
+  public static final class ActivityRule.Builder {
+    ctor public ActivityRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters);
+    method public androidx.window.embedding.ActivityRule build();
+    method public androidx.window.embedding.ActivityRule.Builder setAlwaysExpand(boolean alwaysExpand);
+    method public androidx.window.embedding.ActivityRule.Builder setTag(String? tag);
+  }
+
+  public final class ActivityStack {
+    method public operator boolean contains(android.app.Activity activity);
+    method public boolean isEmpty();
+    property public final boolean isEmpty;
+  }
+
+  public final class EmbeddingAspectRatio {
+    method public static androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_ALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_DISALLOW;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio.Companion Companion;
+  }
+
+  public static final class EmbeddingAspectRatio.Companion {
+    method public androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+  }
+
+  public abstract class EmbeddingRule {
+    method public final String? getTag();
+    property public final String? tag;
+  }
+
+  public final class RuleController {
+    method public void addRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void clearRules();
+    method public static androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> getRules();
+    method public static java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+    method public void removeRule(androidx.window.embedding.EmbeddingRule rule);
+    method public void setRules(java.util.Set<? extends androidx.window.embedding.EmbeddingRule> rules);
+    field public static final androidx.window.embedding.RuleController.Companion Companion;
+  }
+
+  public static final class RuleController.Companion {
+    method public androidx.window.embedding.RuleController getInstance(android.content.Context context);
+    method public java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+  }
+
+  public final class SplitAttributes {
+    method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
+    method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
+    property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
+    property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
+    field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
+  }
+
+  public static final class SplitAttributes.Builder {
+    ctor public SplitAttributes.Builder();
+    method public androidx.window.embedding.SplitAttributes build();
+    method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
+    method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
+  }
+
+  public static final class SplitAttributes.Companion {
+  }
+
+  public static final class SplitAttributes.LayoutDirection {
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection BOTTOM_TO_TOP;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LEFT_TO_RIGHT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LOCALE;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection RIGHT_TO_LEFT;
+    field public static final androidx.window.embedding.SplitAttributes.LayoutDirection TOP_TO_BOTTOM;
+  }
+
+  public static final class SplitAttributes.LayoutDirection.Companion {
+  }
+
+  public static final class SplitAttributes.SplitType {
+    method public static androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+    field public static final androidx.window.embedding.SplitAttributes.SplitType.Companion Companion;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EQUAL;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EXPAND;
+    field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_HINGE;
+  }
+
+  public static final class SplitAttributes.SplitType.Companion {
+    method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+  }
+
+  public final class SplitController {
+    method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+    method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
+    method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+    property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
+    field public static final androidx.window.embedding.SplitController.Companion Companion;
+  }
+
+  public static final class SplitController.Companion {
+    method public androidx.window.embedding.SplitController getInstance(android.content.Context context);
+  }
+
+  public static final class SplitController.SplitSupportStatus {
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus.Companion Companion;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_AVAILABLE;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_ERROR_PROPERTY_NOT_DECLARED;
+    field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_UNAVAILABLE;
+  }
+
+  public static final class SplitController.SplitSupportStatus.Companion {
+  }
+
+  public final class SplitInfo {
+    method public operator boolean contains(android.app.Activity activity);
+    method public androidx.window.embedding.ActivityStack getPrimaryActivityStack();
+    method public androidx.window.embedding.ActivityStack getSecondaryActivityStack();
+    method public androidx.window.embedding.SplitAttributes getSplitAttributes();
+    property public final androidx.window.embedding.ActivityStack primaryActivityStack;
+    property public final androidx.window.embedding.ActivityStack secondaryActivityStack;
+    property public final androidx.window.embedding.SplitAttributes splitAttributes;
+  }
+
+  public final class SplitPairFilter {
+    ctor public SplitPairFilter(android.content.ComponentName primaryActivityName, android.content.ComponentName secondaryActivityName, String? secondaryActivityIntentAction);
+    method public android.content.ComponentName getPrimaryActivityName();
+    method public String? getSecondaryActivityIntentAction();
+    method public android.content.ComponentName getSecondaryActivityName();
+    method public boolean matchesActivityIntentPair(android.app.Activity primaryActivity, android.content.Intent secondaryActivityIntent);
+    method public boolean matchesActivityPair(android.app.Activity primaryActivity, android.app.Activity secondaryActivity);
+    property public final android.content.ComponentName primaryActivityName;
+    property public final String? secondaryActivityIntentAction;
+    property public final android.content.ComponentName secondaryActivityName;
+  }
+
+  public final class SplitPairRule extends androidx.window.embedding.SplitRule {
+    method public boolean getClearTop();
+    method public java.util.Set<androidx.window.embedding.SplitPairFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithSecondary();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishSecondaryWithPrimary();
+    property public final boolean clearTop;
+    property public final java.util.Set<androidx.window.embedding.SplitPairFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary;
+  }
+
+  public static final class SplitPairRule.Builder {
+    ctor public SplitPairRule.Builder(java.util.Set<androidx.window.embedding.SplitPairFilter> filters);
+    method public androidx.window.embedding.SplitPairRule build();
+    method public androidx.window.embedding.SplitPairRule.Builder setClearTop(boolean clearTop);
+    method public androidx.window.embedding.SplitPairRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishPrimaryWithSecondary(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary);
+    method public androidx.window.embedding.SplitPairRule.Builder setFinishSecondaryWithPrimary(androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPairRule.Builder setTag(String? tag);
+  }
+
+  public final class SplitPlaceholderRule extends androidx.window.embedding.SplitRule {
+    method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+    method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithPlaceholder();
+    method public android.content.Intent getPlaceholderIntent();
+    method public boolean isSticky();
+    property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+    property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder;
+    property public final boolean isSticky;
+    property public final android.content.Intent placeholderIntent;
+  }
+
+  public static final class SplitPlaceholderRule.Builder {
+    ctor public SplitPlaceholderRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters, android.content.Intent placeholderIntent);
+    method public androidx.window.embedding.SplitPlaceholderRule build();
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setFinishPrimaryWithPlaceholder(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setSticky(boolean isSticky);
+    method public androidx.window.embedding.SplitPlaceholderRule.Builder setTag(String? tag);
+  }
+
+  public class SplitRule extends androidx.window.embedding.EmbeddingRule {
+    method public final androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInLandscape();
+    method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInPortrait();
+    method public final int getMinHeightDp();
+    method public final int getMinSmallestWidthDp();
+    method public final int getMinWidthDp();
+    property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInLandscape;
+    property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInPortrait;
+    property public final int minHeightDp;
+    property public final int minSmallestWidthDp;
+    property public final int minWidthDp;
+    field public static final androidx.window.embedding.SplitRule.Companion Companion;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT;
+    field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT;
+    field public static final int SPLIT_MIN_DIMENSION_ALWAYS_ALLOW = 0; // 0x0
+    field public static final int SPLIT_MIN_DIMENSION_DP_DEFAULT = 600; // 0x258
+  }
+
+  public static final class SplitRule.Companion {
+  }
+
+  public static final class SplitRule.FinishBehavior {
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ADJACENT;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior ALWAYS;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior.Companion Companion;
+    field public static final androidx.window.embedding.SplitRule.FinishBehavior NEVER;
+  }
+
+  public static final class SplitRule.FinishBehavior.Companion {
+  }
+
+}
+
+package androidx.window.layout {
+
+  public interface DisplayFeature {
+    method public android.graphics.Rect getBounds();
+    property public abstract android.graphics.Rect bounds;
+  }
+
+  public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+    method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.layout.FoldingFeature.State getState();
+    method public boolean isSeparating();
+    property public abstract boolean isSeparating;
+    property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+    property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+    property public abstract androidx.window.layout.FoldingFeature.State state;
+  }
+
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.layout.FoldingFeature.State FLAT;
+    field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public interface WindowInfoTracker {
+    method public default static androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+    method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(android.app.Activity activity);
+    field public static final androidx.window.layout.WindowInfoTracker.Companion Companion;
+  }
+
+  public static final class WindowInfoTracker.Companion {
+    method public androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+  }
+
+  public final class WindowLayoutInfo {
+    method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+    property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+  }
+
+  public final class WindowMetrics {
+    method public android.graphics.Rect getBounds();
+    property public final android.graphics.Rect bounds;
+  }
+
+  public interface WindowMetricsCalculator {
+    method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(@UiContext android.content.Context context);
+    method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+    method public default androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(@UiContext android.content.Context context);
+    method public default static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+    field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+  }
+
+  public static final class WindowMetricsCalculator.Companion {
+    method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+  }
+
+}
+
diff --git a/window/window/src/androidTest/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackendIntegrationTest.kt b/window/window/src/androidTest/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackendIntegrationTest.kt
index 9ec6aa3..46ae397 100644
--- a/window/window/src/androidTest/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackendIntegrationTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/layout/adapter/sidecar/SidecarWindowBackendIntegrationTest.kt
@@ -46,6 +46,7 @@
 import org.junit.Assert.assertTrue
 import org.junit.Assume
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatcher
@@ -155,6 +156,7 @@
         }
     }
 
+    @Ignore // b/277591676
     @Test
     public fun testWindowLayoutUpdatesOnRecreate() {
         assumeExtensionV10_V01()
diff --git a/work/work-benchmark/src/androidTest/java/androidx/work/benchmark/InitializeBenchmark.kt b/work/work-benchmark/src/androidTest/java/androidx/work/benchmark/InitializeBenchmark.kt
index 2835ffa..f89b4cb 100644
--- a/work/work-benchmark/src/androidTest/java/androidx/work/benchmark/InitializeBenchmark.kt
+++ b/work/work-benchmark/src/androidTest/java/androidx/work/benchmark/InitializeBenchmark.kt
@@ -81,7 +81,8 @@
     fun initializeSimple() {
         benchmarkRule.measureRepeated {
             // Runs ForceStopRunnable
-            val database = WorkDatabase.create(context, configuration.taskExecutor, false)
+            val database = WorkDatabase.create(
+                context, configuration.taskExecutor, configuration.clock, false)
             WorkManagerImpl(context, configuration, taskExecutor, database)
             runWithTimingDisabled {
                 executor.runAllCommands()
@@ -95,7 +96,8 @@
     fun initializeWithWorkLeft() {
         val count = 20
         benchmarkRule.measureRepeated {
-            val database = WorkDatabase.create(context, configuration.taskExecutor, false)
+            val database = WorkDatabase.create(
+                context, configuration.taskExecutor, configuration.clock, false)
             runWithTimingDisabled {
                 for (i in 0 until count) {
                     val request = OneTimeWorkRequestBuilder<NoOpWorker>()
diff --git a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
index 361480bf..e28fc49 100644
--- a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
+++ b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
@@ -77,7 +77,7 @@
         mScheduler = mock(Scheduler::class.java)
         mForegroundProcessor = mock(ForegroundProcessor::class.java)
         mWorkManager = mock(WorkManagerImpl::class.java)
-        mDatabase = WorkDatabase.create(mContext, mExecutor, true)
+        mDatabase = WorkDatabase.create(mContext, mExecutor, mConfiguration.clock, true)
         val schedulers = listOf(mScheduler)
         // Processor
         mProcessor = Processor(mContext, mConfiguration, mTaskExecutor, mDatabase)
diff --git a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
index 6f3be41..5efb197 100644
--- a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
+++ b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
@@ -83,7 +83,7 @@
         mScheduler = mock(Scheduler::class.java)
         mForegroundProcessor = mock(ForegroundProcessor::class.java)
         mWorkManager = mock(WorkManagerImpl::class.java)
-        mDatabase = WorkDatabase.create(mContext, mExecutor, true)
+        mDatabase = WorkDatabase.create(mContext, mExecutor, mConfiguration.clock, true)
         val schedulers = listOf(mScheduler)
         // Processor
         mProcessor = Processor(mContext, mConfiguration, mTaskExecutor, mDatabase)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/ContentUriTriggerWorkersTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/ContentUriTriggerWorkersTest.kt
index c9bf3cb..35f3978 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/ContentUriTriggerWorkersTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/ContentUriTriggerWorkersTest.kt
@@ -54,7 +54,7 @@
         context = context,
         configuration = configuration,
         workTaskExecutor = taskExecutor,
-        workDatabase = WorkDatabase.create(context, executor, true),
+        workDatabase = WorkDatabase.create(context, executor, configuration.clock, true),
         schedulersCreator = schedulers(testScheduler)
     )
 
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/DatabaseTest.java b/work/work-runtime/src/androidTest/java/androidx/work/DatabaseTest.java
index e7d6c4a..db0c7db 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/DatabaseTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/DatabaseTest.java
@@ -42,6 +42,7 @@
         mDatabase = WorkDatabase.create(
                 ApplicationProvider.getApplicationContext(),
                 mQueryExecutor,
+                new SystemClock(), // only used for the pruning task
                 true);
     }
 
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/SchedulersTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/SchedulersTest.kt
index 21a8de2..aa90135 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/SchedulersTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/SchedulersTest.kt
@@ -49,7 +49,8 @@
     val factory = TrackingWorkerFactory()
     val configuration = Configuration.Builder().setWorkerFactory(factory).build()
     val taskExecutor = WorkManagerTaskExecutor(configuration.taskExecutor)
-    val db = WorkDatabase.create(context, taskExecutor.serialTaskExecutor, true)
+    val db = WorkDatabase.create(
+        context, taskExecutor.serialTaskExecutor, configuration.clock, true)
     val processor = Processor(context, configuration, taskExecutor, db)
     val launcher = WorkLauncherImpl(processor, taskExecutor)
     val trackers = Trackers(context, taskExecutor)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/WorkInfoFlowsTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/WorkInfoFlowsTest.kt
index 10b44d3..ac28b7b 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/WorkInfoFlowsTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/WorkInfoFlowsTest.kt
@@ -62,7 +62,7 @@
         taskExecutor = taskExecutor,
         batteryChargingTracker = fakeChargingTracker
     )
-    val db = WorkDatabase.create(context, executor, true)
+    val db = WorkDatabase.create(context, executor, configuration.clock, true)
 
     // ugly, ugly hack because of circular dependency:
     // Schedulers need WorkManager, WorkManager needs schedulers
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
index 2084fdd..b150905 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
@@ -65,7 +65,7 @@
         taskExecutor = taskExecutor,
         batteryChargingTracker = fakeChargingTracker
     )
-    val db = WorkDatabase.create(context, executor, true)
+    val db = WorkDatabase.create(context, executor, configuration.clock, true)
 
     val processor = Processor(context, configuration, taskExecutor, db)
     val launcher = WorkLauncherImpl(processor, taskExecutor)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
index 6e80617..4bb7dc3 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
@@ -29,6 +29,7 @@
 import androidx.work.ListenableWorker.Result
 import androidx.work.OneTimeWorkRequest
 import androidx.work.OutOfQuotaPolicy
+import androidx.work.SystemClock
 import androidx.work.WorkerFactory
 import androidx.work.WorkerParameters
 import androidx.work.impl.foreground.ForegroundProcessor
@@ -48,7 +49,7 @@
     private val taskExecutor = ManualTaskExecutor()
     private val backgroundExecutor = ManualExecutor()
     private val workDatabase = WorkDatabase.create(
-        context, taskExecutor.serialTaskExecutor, true
+        context, taskExecutor.serialTaskExecutor, SystemClock(), true
     )
     private val foregroundInfoFuture = SettableFuture.create<ForegroundInfo>()
     private val resultFuture = SettableFuture.create<Result>().also { it.set(Result.success()) }
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/SchedulersTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/SchedulersTest.java
index a0a03ab..b6b1e32 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/SchedulersTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/SchedulersTest.java
@@ -45,8 +45,8 @@
 
     private final Context mAppContext = ApplicationProvider.getApplicationContext();
     private final Configuration mConfiguration = new Configuration.Builder().build();
-    private final WorkDatabase mWorkDatabase = WorkDatabase.create(mAppContext,
-            mConfiguration.getExecutor(), false);
+    private final WorkDatabase mWorkDatabase = WorkDatabase.create(
+            mAppContext, mConfiguration.getExecutor(), mConfiguration.getClock(), false);
 
     @FlakyTest(bugId = 206647994)
     @Test
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
index 8b4a84c..0528bf1 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkManagerImplTest.java
@@ -85,6 +85,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.testutils.RepeatRule;
 import androidx.work.BackoffPolicy;
+import androidx.work.Clock;
 import androidx.work.Configuration;
 import androidx.work.Constraints;
 import androidx.work.Constraints.ContentUriTrigger;
@@ -141,6 +142,7 @@
 
     private Context mContext;
     private Configuration mConfiguration;
+    private OverrideClock mClock = new OverrideClock();
     private WorkDatabase mDatabase;
     private Scheduler mScheduler;
     private WorkManagerImpl mWorkManagerImpl;
@@ -169,6 +171,7 @@
         mContext = ApplicationProvider.getApplicationContext();
         mConfiguration = new Configuration.Builder()
                 .setExecutor(Executors.newSingleThreadExecutor())
+                .setClock(mClock)
                 .setMinimumLoggingLevel(Log.DEBUG)
                 .build();
         InstantWorkTaskExecutor workTaskExecutor = new InstantWorkTaskExecutor();
@@ -1837,13 +1840,17 @@
     @Test
     @MediumTest
     public void testGenerateCleanupCallback_deletesOldFinishedWork() {
+        long nowMillis = TimeUnit.DAYS.toMillis(30);
+        mClock.mOverrideTimeMillis = nowMillis;
+
         OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
                 .setInitialState(SUCCEEDED)
-                .setLastEnqueueTime(CleanupCallback.INSTANCE.getPruneDate() - 1L,
+                .setLastEnqueueTime(nowMillis - WorkDatabaseKt.PRUNE_THRESHOLD_MILLIS - 1L,
                         TimeUnit.MILLISECONDS)
                 .build();
         OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
-                .setLastEnqueueTime(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
+                .setLastEnqueueTime(nowMillis - WorkDatabaseKt.PRUNE_THRESHOLD_MILLIS + 1L,
+                        TimeUnit.MILLISECONDS)
                 .build();
 
         insertWorkSpecAndTags(work1);
@@ -1851,7 +1858,8 @@
 
         SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper();
         SupportSQLiteDatabase db = openHelper.getWritableDatabase();
-        CleanupCallback.INSTANCE.onOpen(db);
+
+        new CleanupCallback(mClock).onOpen(db);
 
         WorkSpecDao workSpecDao = mDatabase.workSpecDao();
         assertThat(workSpecDao.getWorkSpec(work1.getStringId()), is(nullValue()));
@@ -1861,19 +1869,22 @@
     @Test
     @MediumTest
     public void testGenerateCleanupCallback_doesNotDeleteOldFinishedWorkWithActiveDependents() {
+        long nowMillis = TimeUnit.DAYS.toMillis(30);
+        mClock.mOverrideTimeMillis = nowMillis;
+
         OneTimeWorkRequest work0 = new OneTimeWorkRequest.Builder(TestWorker.class)
                 .setInitialState(SUCCEEDED)
-                .setLastEnqueueTime(CleanupCallback.INSTANCE.getPruneDate() - 1L,
+                .setLastEnqueueTime(nowMillis - WorkDatabaseKt.PRUNE_THRESHOLD_MILLIS - 1L,
                         TimeUnit.MILLISECONDS)
                 .build();
         OneTimeWorkRequest work1 = new OneTimeWorkRequest.Builder(TestWorker.class)
                 .setInitialState(SUCCEEDED)
-                .setLastEnqueueTime(CleanupCallback.INSTANCE.getPruneDate() - 1L,
+                .setLastEnqueueTime(nowMillis - WorkDatabaseKt.PRUNE_THRESHOLD_MILLIS - 1L,
                         TimeUnit.MILLISECONDS)
                 .build();
         OneTimeWorkRequest work2 = new OneTimeWorkRequest.Builder(TestWorker.class)
                 .setInitialState(ENQUEUED)
-                .setLastEnqueueTime(CleanupCallback.INSTANCE.getPruneDate() - 1L,
+                .setLastEnqueueTime(nowMillis - WorkDatabaseKt.PRUNE_THRESHOLD_MILLIS - 1L,
                         TimeUnit.MILLISECONDS)
                 .build();
 
@@ -1887,7 +1898,8 @@
 
         SupportSQLiteOpenHelper openHelper = mDatabase.getOpenHelper();
         SupportSQLiteDatabase db = openHelper.getWritableDatabase();
-        CleanupCallback.INSTANCE.onOpen(db);
+
+        new CleanupCallback(mClock).onOpen(db);
 
         WorkSpecDao workSpecDao = mDatabase.workSpecDao();
         assertThat(workSpecDao.getWorkSpec(work0.getStringId()), is(nullValue()));
@@ -2151,4 +2163,14 @@
                 Long.MAX_VALUE // Documented error value.
         );
     }
+
+    private class OverrideClock implements Clock {
+        long mOverrideTimeMillis = Long.MAX_VALUE;
+
+        @Override
+        public long currentTimeMillis() {
+            return mOverrideTimeMillis == Long.MAX_VALUE ? System.currentTimeMillis()
+                    : mOverrideTimeMillis;
+        }
+    }
 }
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/DelayedWorkTrackerTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/DelayedWorkTrackerTest.kt
index 80e0f0a..ffce534 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/DelayedWorkTrackerTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/DelayedWorkTrackerTest.kt
@@ -52,7 +52,7 @@
         builder.setLastEnqueueTime(now, TimeUnit.MILLISECONDS)
         builder.setInitialDelay(delay, TimeUnit.MILLISECONDS)
         val request = builder.build()
-        mDelayedWorkTracker.schedule(request.workSpec)
+        mDelayedWorkTracker.schedule(request.workSpec, now + delay)
 
         verify(mRunnableScheduler).scheduleWithDelay(
             anyLong(),
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
index 393685e..4783799 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/greedy/GreedySchedulerTest.java
@@ -16,10 +16,13 @@
 
 package androidx.work.impl.background.greedy;
 
+import static androidx.work.WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS;
 import static androidx.work.impl.model.WorkSpecKt.generationalId;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -115,7 +118,7 @@
                 .setInitialDelay(1000L, TimeUnit.MILLISECONDS)
                 .build();
         mGreedyScheduler.schedule(work.getWorkSpec());
-        verify(mDelayedWorkTracker).schedule(work.getWorkSpec());
+        verify(mDelayedWorkTracker).schedule(eq(work.getWorkSpec()), anyLong());
     }
 
     @Test
@@ -126,7 +129,7 @@
                 .setInitialRunAttemptCount(5)
                 .build();
         mGreedyScheduler.schedule(work.getWorkSpec());
-        verify(mDelayedWorkTracker).schedule(work.getWorkSpec());
+        verify(mDelayedWorkTracker).schedule(eq(work.getWorkSpec()), anyLong());
     }
 
     @Test
@@ -215,4 +218,24 @@
         verify(mMockProcessor, times(0)).addExecutionListener(mGreedyScheduler);
         verify(mMockWorkConstraintsTracker, never()).replace(ArgumentMatchers.<WorkSpec>anyList());
     }
+
+    @Test
+    @SmallTest
+    public void testGreedyScheduler_throttleWork() {
+        long before = System.currentTimeMillis();
+        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class)
+                .setLastEnqueueTime(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
+                .setInitialDelay(1000L, TimeUnit.MILLISECONDS)
+                .build();
+        WorkSpec workSpec = work.getWorkSpec();
+        mGreedyScheduler.schedule(workSpec);
+        mGreedyScheduler.onExecuted(generationalId(workSpec), true);
+        WorkSpec updatedRunAttemptCount = new WorkSpec(workSpec.id, workSpec);
+        updatedRunAttemptCount.runAttemptCount = 10;
+        reset(mDelayedWorkTracker);
+        mGreedyScheduler.schedule(updatedRunAttemptCount);
+        ArgumentCaptor<Long> delayCapture = ArgumentCaptor.forClass(Long.class);
+        verify(mDelayedWorkTracker).schedule(eq(updatedRunAttemptCount), delayCapture.capture());
+        assertThat(delayCapture.getValue()).isAtLeast(before + 5 * DEFAULT_BACKOFF_DELAY_MILLIS);
+    }
 }
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
index 8356427..b2ee927 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
@@ -104,11 +104,12 @@
         });
 
         Context context = ApplicationProvider.getApplicationContext();
-        mDatabase = WorkDatabase.create(context, Executors.newCachedThreadPool(), true);
-        InstantWorkTaskExecutor taskExecutor = new InstantWorkTaskExecutor();
         Configuration configuration = new Configuration.Builder()
                 .setExecutor(Executors.newSingleThreadExecutor())
                 .build();
+        mDatabase = WorkDatabase.create(
+                context, Executors.newCachedThreadPool(), configuration.getClock(), true);
+        InstantWorkTaskExecutor taskExecutor = new InstantWorkTaskExecutor();
         mScheduler = mock(Scheduler.class);
         mProcessor = new Processor(
                 context,
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
index ed29b21..2227d29 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
@@ -92,7 +92,8 @@
             .build()
         taskExecutor = InstantWorkTaskExecutor()
         val scheduler = mock(Scheduler::class.java)
-        workDatabase = WorkDatabase.create(context, taskExecutor.serialTaskExecutor, true)
+        workDatabase = WorkDatabase.create(
+            context, taskExecutor.serialTaskExecutor, config.clock, true)
         processor = spy(Processor(context, config, taskExecutor, workDatabase))
         workManager = spy(
             WorkManagerImpl(
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
index 159a514..e9b15b1 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
@@ -82,7 +82,8 @@
 
         taskExecutor = WorkManagerTaskExecutor(internalExecutor)
 
-        workDatabase = WorkDatabase.create(context, taskExecutor.serialTaskExecutor, true)
+        workDatabase = WorkDatabase.create(
+            context, taskExecutor.serialTaskExecutor, config.clock, true)
         workManager = WorkManagerImpl(
                 context = context,
                 configuration = config,
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
index d008959..d185a21 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/utils/ForceStopRunnableTest.java
@@ -89,7 +89,8 @@
                 .setExecutor(executor)
                 .setTaskExecutor(executor)
                 .build();
-        mWorkDatabase = WorkDatabase.create(mContext, mConfiguration.getTaskExecutor(), true);
+        mWorkDatabase = WorkDatabase.create(
+                mContext, mConfiguration.getTaskExecutor(), mConfiguration.getClock(), true);
         when(mWorkManager.getWorkDatabase()).thenReturn(mWorkDatabase);
         when(mWorkManager.getSchedulers()).thenReturn(Collections.singletonList(mScheduler));
         when(mWorkManager.getPreferenceUtils()).thenReturn(mPreferenceUtils);
@@ -210,7 +211,8 @@
         mContext = mock(Context.class);
         when(mContext.getApplicationContext()).thenReturn(mContext);
         when(mContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(mActivityManager);
-        mWorkDatabase = WorkDatabase.create(mContext, mConfiguration.getTaskExecutor(), true);
+        mWorkDatabase = WorkDatabase.create(
+                mContext, mConfiguration.getTaskExecutor(), mConfiguration.getClock(), true);
         when(mWorkManager.getWorkDatabase()).thenReturn(mWorkDatabase);
         mRunnable = new ForceStopRunnable(mContext, mWorkManager);
 
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt b/work/work-runtime/src/main/java/androidx/work/Clock.java
similarity index 67%
copy from bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
copy to work/work-runtime/src/main/java/androidx/work/Clock.java
index 84d9567..5ca1a98 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/data/SampleAdvertiseData.kt
+++ b/work/work-runtime/src/main/java/androidx/work/Clock.java
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-package androidx.bluetooth.integration.testapp.data
+package androidx.work;
 
-import android.os.ParcelUuid
+import androidx.annotation.RestrictTo;
 
-object SampleAdvertiseData {
-    val testUUID: ParcelUuid =
-        ParcelUuid.fromString("00000000-0000-0000-0000-000000000001")
+/**
+ * The interface WorkManager uses to access to the current time.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface Clock {
+    /** @see java.lang.System#currentTimeMillis */
+    long currentTimeMillis();
 }
diff --git a/work/work-runtime/src/main/java/androidx/work/Configuration.kt b/work/work-runtime/src/main/java/androidx/work/Configuration.kt
index a9c2810..5d4d29e 100644
--- a/work/work-runtime/src/main/java/androidx/work/Configuration.kt
+++ b/work/work-runtime/src/main/java/androidx/work/Configuration.kt
@@ -49,6 +49,12 @@
     val taskExecutor: Executor
 
     /**
+     * The [Clock] used by [WorkManager] to calculate schedules and perform book-keeping.
+     */
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    val clock: Clock
+
+    /**
      * The [WorkerFactory] used by [WorkManager] to create [ListenableWorker]s
      */
     val workerFactory: WorkerFactory
@@ -139,6 +145,7 @@
         // So this should not be a single threaded executor. Writes will still be serialized
         // as this will be wrapped with an SerialExecutor.
         taskExecutor = builder.taskExecutor ?: createDefaultExecutor(isTaskExecutor = true)
+        clock = builder.clock ?: SystemClock()
         workerFactory = builder.workerFactory ?: WorkerFactory.getDefaultWorkerFactory()
         inputMergerFactory = builder.inputMergerFactory ?: NoOpInputMergerFactory
         runnableScheduler = builder.runnableScheduler ?: DefaultRunnableScheduler()
@@ -165,6 +172,7 @@
         internal var workerFactory: WorkerFactory? = null
         internal var inputMergerFactory: InputMergerFactory? = null
         internal var taskExecutor: Executor? = null
+        internal var clock: Clock? = null
         internal var runnableScheduler: RunnableScheduler? = null
         internal var initializationExceptionHandler: Consumer<Throwable>? = null
         internal var schedulingExceptionHandler: Consumer<Throwable>? = null
@@ -194,6 +202,7 @@
             workerFactory = configuration.workerFactory
             inputMergerFactory = configuration.inputMergerFactory
             taskExecutor = configuration.taskExecutor
+            clock = configuration.clock
             loggingLevel = configuration.minimumLoggingLevel
             minJobSchedulerId = configuration.minJobSchedulerId
             maxJobSchedulerId = configuration.maxJobSchedulerId
@@ -255,6 +264,18 @@
         }
 
         /**
+         * Sets a [Clock] for WorkManager to calculate schedules and perform book-keeping.
+         *
+         * @param clock The [Clock] to use
+         * @return This [Builder] instance
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        fun setClock(clock: Clock): Builder {
+            this.clock = clock
+            return this
+        }
+
+        /**
          * Specifies the range of [android.app.job.JobInfo] IDs that can be used by
          * [WorkManager].  WorkManager needs a range of at least `1000` IDs.
          *
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt b/work/work-runtime/src/main/java/androidx/work/SystemClock.java
similarity index 64%
copy from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
copy to work/work-runtime/src/main/java/androidx/work/SystemClock.java
index f01729c..b9f503e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
+++ b/work/work-runtime/src/main/java/androidx/work/SystemClock.java
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
-package androidx.appactions.interaction.capabilities.core
+package androidx.work;
+
+import androidx.annotation.RestrictTo;
 
 /**
- * InitArg contains data passed to {@code BaseSession#onInit}.
+ * A default clock that returns the real time from the Java System clock.
  */
-class InitArg internal constructor() {
-    override fun toString() =
-        "InitArg()"
-
-    override fun equals(other: Any?): Boolean {
-        return other is InitArg
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class SystemClock implements Clock {
+    /** @inheritDoc */
+    @Override
+    public long currentTimeMillis() {
+        return System.currentTimeMillis();
     }
 }
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkDatabase.kt b/work/work-runtime/src/main/java/androidx/work/impl/WorkDatabase.kt
index 2e1b4bf..3cff9d7 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkDatabase.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkDatabase.kt
@@ -25,6 +25,7 @@
 import androidx.sqlite.db.SupportSQLiteDatabase
 import androidx.sqlite.db.SupportSQLiteOpenHelper
 import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
+import androidx.work.Clock
 import androidx.work.Data
 import androidx.work.impl.WorkDatabaseVersions.VERSION_10
 import androidx.work.impl.WorkDatabaseVersions.VERSION_11
@@ -116,6 +117,7 @@
          * @param context         A context (this method will use the application context from it)
          * @param queryExecutor   An [Executor] that will be used to execute all async Room
          * queries.
+         * @param clock           The [Clock] to use for pruning operations
          * @param useTestDatabase `true` to generate an in-memory database that allows main thread
          * access
          * @return The created WorkDatabase
@@ -124,6 +126,7 @@
         fun create(
             context: Context,
             queryExecutor: Executor,
+            clock: Clock,
             useTestDatabase: Boolean
         ): WorkDatabase {
             val builder = if (useTestDatabase) {
@@ -141,7 +144,7 @@
                     }
             }
             return builder.setQueryExecutor(queryExecutor)
-                .addCallback(CleanupCallback)
+                .addCallback(CleanupCallback(clock))
                 .addMigrations(Migration_1_2)
                 .addMigrations(RescheduleMigration(context, VERSION_2, VERSION_3))
                 .addMigrations(Migration_3_4)
@@ -175,14 +178,17 @@
     "    prerequisite_id=id AND " +
     "    work_spec_id NOT IN " +
     "        (SELECT id FROM workspec WHERE state IN $COMPLETED_STATES))"
-private val PRUNE_THRESHOLD_MILLIS = TimeUnit.DAYS.toMillis(1)
 
-internal object CleanupCallback : RoomDatabase.Callback() {
+@JvmField
+val PRUNE_THRESHOLD_MILLIS: Long = TimeUnit.DAYS.toMillis(1)
+
+internal class CleanupCallback(val clock: Clock) : RoomDatabase.Callback() {
+
     private val pruneSQL: String
         get() = "$PRUNE_SQL_FORMAT_PREFIX$pruneDate$PRUNE_SQL_FORMAT_SUFFIX"
 
-    val pruneDate: Long
-        get() = System.currentTimeMillis() - PRUNE_THRESHOLD_MILLIS
+    private val pruneDate: Long
+        get() = clock.currentTimeMillis() - PRUNE_THRESHOLD_MILLIS
 
     override fun onOpen(db: SupportSQLiteDatabase) {
         super.onOpen(db)
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkManagerImplExt.kt b/work/work-runtime/src/main/java/androidx/work/impl/WorkManagerImplExt.kt
index d27ca51..f09b0a6 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkManagerImplExt.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkManagerImplExt.kt
@@ -33,6 +33,7 @@
     workDatabase: WorkDatabase =
         WorkDatabase.create(
             context.applicationContext, workTaskExecutor.serialTaskExecutor,
+            configuration.clock,
             context.resources.getBoolean(R.bool.workmanager_test_configuration)
         ),
     trackers: Trackers = Trackers(context.applicationContext, workTaskExecutor),
@@ -58,7 +59,7 @@
     workTaskExecutor: TaskExecutor,
 ) = WorkManagerImpl(
     context, configuration, workTaskExecutor,
-    WorkDatabase.create(context, workTaskExecutor.serialTaskExecutor, true)
+    WorkDatabase.create(context, workTaskExecutor.serialTaskExecutor, configuration.clock, true)
 )
 
 internal typealias SchedulersCreator = (
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
index bb3f931..3d131f87 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -33,6 +33,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
+import androidx.work.Clock;
 import androidx.work.Configuration;
 import androidx.work.Data;
 import androidx.work.InputMerger;
@@ -90,6 +91,7 @@
     ListenableWorker.Result mResult = ListenableWorker.Result.failure();
 
     private Configuration mConfiguration;
+    private Clock mClock;
     private ForegroundProcessor mForegroundProcessor;
     private WorkDatabase mWorkDatabase;
     private WorkSpecDao mWorkSpecDao;
@@ -120,6 +122,7 @@
         mWorker = builder.mWorker;
 
         mConfiguration = builder.mConfiguration;
+        mClock = builder.mConfiguration.getClock();
         mWorkDatabase = builder.mWorkDatabase;
         mWorkSpecDao = mWorkDatabase.workSpecDao();
         mDependencyDao = mWorkDatabase.dependencyDao();
@@ -177,7 +180,7 @@
             // Also potential bugs in the platform may cause a Job to run more than once.
 
             if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
-                long now = System.currentTimeMillis();
+                long now = mClock.currentTimeMillis();
                 if (now < mWorkSpec.calculateNextRunTime()) {
                     Logger.get().debug(TAG,
                             String.format(
@@ -533,7 +536,7 @@
         mWorkDatabase.beginTransaction();
         try {
             mWorkSpecDao.setState(ENQUEUED, mWorkSpecId);
-            mWorkSpecDao.setLastEnqueueTime(mWorkSpecId, System.currentTimeMillis());
+            mWorkSpecDao.setLastEnqueueTime(mWorkSpecId, mClock.currentTimeMillis());
             mWorkSpecDao.markWorkSpecScheduled(mWorkSpecId, SCHEDULE_NOT_REQUESTED_YET);
             mWorkDatabase.setTransactionSuccessful();
         } finally {
@@ -549,7 +552,7 @@
             // Therefore we always use the current time to determine the next run time of a Worker.
             // This way, the Schedulers will correctly schedule the next instance of the
             // PeriodicWork in the future. This happens in calculateNextRunTime() in WorkSpec.
-            mWorkSpecDao.setLastEnqueueTime(mWorkSpecId, System.currentTimeMillis());
+            mWorkSpecDao.setLastEnqueueTime(mWorkSpecId, mClock.currentTimeMillis());
             mWorkSpecDao.setState(ENQUEUED, mWorkSpecId);
             mWorkSpecDao.resetWorkSpecRunAttemptCount(mWorkSpecId);
             mWorkSpecDao.incrementPeriodCount(mWorkSpecId);
@@ -571,7 +574,7 @@
             mWorkSpecDao.setOutput(mWorkSpecId, output);
 
             // Unblock Dependencies and set Period Start Time
-            long currentTimeMillis = System.currentTimeMillis();
+            long currentTimeMillis = mClock.currentTimeMillis();
             List<String> dependentWorkIds = mDependencyDao.getDependentWorkIds(mWorkSpecId);
             for (String dependentWorkId : dependentWorkIds) {
                 if (mWorkSpecDao.getState(dependentWorkId) == BLOCKED
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/DelayedWorkTracker.java b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/DelayedWorkTracker.java
index 523da2c..01e484a 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/DelayedWorkTracker.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/DelayedWorkTracker.java
@@ -60,8 +60,9 @@
      * the {@link WorkSpec}'s scheduled run time.
      *
      * @param workSpec The {@link WorkSpec} corresponding to the {@link androidx.work.WorkRequest}
+     * @param nextRunTime time when work should be executed
      */
-    public void schedule(@NonNull final WorkSpec workSpec) {
+    public void schedule(@NonNull final WorkSpec workSpec, long nextRunTime) {
         Runnable existing = mRunnables.remove(workSpec.id);
         if (existing != null) {
             mRunnableScheduler.cancel(existing);
@@ -77,7 +78,7 @@
 
         mRunnables.put(workSpec.id, runnable);
         long now = System.currentTimeMillis();
-        long delay = workSpec.calculateNextRunTime() - now;
+        long delay = nextRunTime - now;
         mRunnableScheduler.scheduleWithDelay(delay, runnable);
     }
 
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
index 61dc2bb..b7e8767 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/background/greedy/GreedyScheduler.java
@@ -18,8 +18,11 @@
 
 import static android.os.Build.VERSION.SDK_INT;
 
+import static androidx.work.WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS;
 import static androidx.work.impl.model.WorkSpecKt.generationalId;
 
+import static java.lang.Math.max;
+
 import android.content.Context;
 import android.text.TextUtils;
 
@@ -43,21 +46,28 @@
 import androidx.work.impl.model.WorkSpec;
 import androidx.work.impl.utils.ProcessUtils;
 
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
  * A greedy {@link Scheduler} that schedules unconstrained, non-timed work.  It intentionally does
  * not acquire any WakeLocks, instead trying to brute-force them as time allows before the process
  * gets killed.
- *
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class GreedyScheduler implements Scheduler, WorkConstraintsCallback, ExecutionListener {
 
     private static final String TAG = Logger.tagWithPrefix("GreedyScheduler");
 
+    /**
+     * GreedyScheduler will start throttle workspec if it sees the same work being retried
+     * within process's lifetime.
+     */
+    private static final int NON_THROTTLE_RUN_ATTEMPT_COUNT = 5;
+
     private final Context mContext;
     private final WorkConstraintsTracker mWorkConstraintsTracker;
     private final Set<WorkSpec> mConstrainedWorkSpecs = new HashSet<>();
@@ -69,6 +79,8 @@
     private final WorkLauncher mWorkLauncher;
 
     private final Configuration mConfiguration;
+
+    private final Map<WorkGenerationalId, AttemptData> mFirstRunAttempts = new HashMap<>();
     // Internal State
     Boolean mInDefaultProcess;
 
@@ -138,13 +150,14 @@
             if (mStartStopTokens.contains(id)) {
                 continue;
             }
-            long nextRunTime = workSpec.calculateNextRunTime();
+            long throttled = throttleIfNeeded(workSpec);
+            long nextRunTime = max(workSpec.calculateNextRunTime(), throttled);
             long now = System.currentTimeMillis();
             if (workSpec.state == WorkInfo.State.ENQUEUED) {
                 if (now < nextRunTime) {
                     // Future work
                     if (mDelayedWorkTracker != null) {
-                        mDelayedWorkTracker.schedule(workSpec);
+                        mDelayedWorkTracker.schedule(workSpec, nextRunTime);
                     }
                 } else if (workSpec.hasConstraints()) {
                     if (SDK_INT >= 23 && workSpec.constraints.requiresDeviceIdle()) {
@@ -202,7 +215,7 @@
             mDelayedWorkTracker.unschedule(workSpecId);
         }
         // onExecutionCompleted does the cleanup.
-        for (StartStopToken id: mStartStopTokens.remove(workSpecId)) {
+        for (StartStopToken id : mStartStopTokens.remove(workSpecId)) {
             mWorkLauncher.stopWork(id);
         }
     }
@@ -235,6 +248,13 @@
     public void onExecuted(@NonNull WorkGenerationalId id, boolean needsReschedule) {
         mStartStopTokens.remove(id);
         removeConstraintTrackingFor(id);
+
+        if (!needsReschedule) {
+            // finished execution rather than being interrupted
+            synchronized (mLock) {
+                mFirstRunAttempts.remove(id);
+            }
+        }
         // onExecuted does not need to worry about unscheduling WorkSpecs with the mDelayedTracker.
         // This is because, after onExecuted(), all schedulers are asked to cancel.
     }
@@ -263,4 +283,29 @@
             mRegisteredExecutionListener = true;
         }
     }
+
+    private long throttleIfNeeded(WorkSpec workSpec) {
+        synchronized (mLock) {
+            WorkGenerationalId id = generationalId(workSpec);
+            AttemptData firstRunAttempt = mFirstRunAttempts.get(id);
+            if (firstRunAttempt == null) {
+                firstRunAttempt = new AttemptData(workSpec.runAttemptCount,
+                        System.currentTimeMillis());
+                mFirstRunAttempts.put(id, firstRunAttempt);
+            }
+            return firstRunAttempt.mTimeStamp
+                    + max(workSpec.runAttemptCount - firstRunAttempt.mRunAttemptCount
+                    - NON_THROTTLE_RUN_ATTEMPT_COUNT, 0) * DEFAULT_BACKOFF_DELAY_MILLIS;
+        }
+    }
+
+    private static class AttemptData {
+        final int mRunAttemptCount;
+        final long mTimeStamp;
+
+        private AttemptData(int runAttemptCount, long timeStamp) {
+            this.mRunAttemptCount = runAttemptCount;
+            this.mTimeStamp = timeStamp;
+        }
+    }
 }
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
index efe451d..c1c136f 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpec.kt
@@ -452,30 +452,22 @@
                         .toLong()
                 lastEnqueueTime + delay.coerceAtMost(WorkRequest.MAX_BACKOFF_MILLIS)
             } else if (isPeriodic) {
-                val start =
-                    if (periodCount == 0) lastEnqueueTime + initialDelay else lastEnqueueTime
+                // The first run of a periodic work request is immediate in JobScheduler, so
+                // don't apply intervalDuration to the first run.
+                var schedule =
+                    if (periodCount == 0) lastEnqueueTime + initialDelay
+                    else lastEnqueueTime + intervalDuration
+
                 val isFlexApplicable = flexDuration != intervalDuration
-                if (isFlexApplicable) {
-                    // To correctly emulate flex, we need to set it
-                    // to now, so the PeriodicWorkRequest has an initial delay of
-                    // initialDelay + (interval - flex).
-
-                    // The subsequent runs will only add the interval duration and no flex.
-                    // This gives us the following behavior:
-                    // 1 => now + (interval - flex) + initialDelay = firstRunTime
-                    // 2 => firstRunTime + 2 * interval - flex
-                    // 3 => firstRunTime + 3 * interval - flex
-                    val offset = if (periodCount == 0) -1 * flexDuration else 0
-                    start + intervalDuration + offset
-                } else {
-                    // Don't use flexDuration for determining next run time for PeriodicWork
-                    // This is because intervalDuration could equal flexDuration.
-
-                    // The first run of a periodic work request is immediate in JobScheduler, and we
-                    // need to emulate this behavior.
-                    val offset = if (periodCount == 0) 0 else intervalDuration
-                    start + offset
+                // Flex only applies to the first run of a Periodic worker, to avoid
+                // repeatedly pushing the schedule forward on every period.
+                if (isFlexApplicable && periodCount == 0) {
+                    // With flex, the first run does not run immediately, but instead respects
+                    // the first interval duration.
+                    schedule += (intervalDuration - flexDuration)
                 }
+
+                schedule
             } else if (lastEnqueueTime == 0L) {
                 // If never enqueued, we aren't scheduled to run.
                 Long.MAX_VALUE // 200 million years.
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
index c0ae702..3b42be9 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/EnqueueRunnable.java
@@ -188,7 +188,7 @@
 
         boolean needsScheduling = false;
 
-        long currentTimeMillis = System.currentTimeMillis();
+        long currentTimeMillis = workManagerImpl.getConfiguration().getClock().currentTimeMillis();
         WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();
 
         boolean hasPrerequisite = (prerequisiteIds != null && prerequisiteIds.length > 0);
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
index 75a9d84..71a2547 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
@@ -248,7 +248,8 @@
             Logger.get().debug(TAG, "Application was force-stopped, rescheduling.");
             mWorkManager.rescheduleEligibleWork();
             // Update the last known force-stop event timestamp.
-            mPreferenceUtils.setLastForceStopEventMillis(System.currentTimeMillis());
+            mPreferenceUtils.setLastForceStopEventMillis(
+                    mWorkManager.getConfiguration().getClock().currentTimeMillis());
         } else if (needsScheduling) {
             Logger.get().debug(TAG, "Found unfinished work, scheduling it.");
             Schedulers.schedule(
@@ -379,6 +380,8 @@
             flags |= FLAG_MUTABLE;
         }
         PendingIntent pendingIntent = getPendingIntent(context, flags);
+        // OK to use System.currentTimeMillis() since this is intended only to keep the alarm
+        // scheduled ~forever and shouldn't need WorkManager to be initialized to reschedule.
         long triggerAt = System.currentTimeMillis() + TEN_YEARS;
         if (alarmManager != null) {
             if (Build.VERSION.SDK_INT >= 19) {
diff --git a/work/work-testing/src/androidTest/java/androidx/work/testing/CustomClockTest.kt b/work/work-testing/src/androidTest/java/androidx/work/testing/CustomClockTest.kt
new file mode 100644
index 0000000..101c334
--- /dev/null
+++ b/work/work-testing/src/androidTest/java/androidx/work/testing/CustomClockTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.testing
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.work.Configuration
+import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkRequest
+import androidx.work.impl.WorkManagerImpl
+import androidx.work.testing.workers.TestWorker
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.util.concurrent.ExecutionException
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class CustomClockTest {
+    private val testClock = TestClock(/* timeMillis= */ 1000)
+
+    private lateinit var mContext: Context
+    private lateinit var mTestDriver: TestDriver
+    private lateinit var mHandler: Handler
+
+    @Before
+    fun setUp() {
+        mContext = ApplicationProvider.getApplicationContext()
+        mHandler = Handler(Looper.getMainLooper())
+        val configuration =
+            Configuration.Builder().setExecutor(androidx.work.testing.SynchronousExecutor())
+                .setClock(testClock).setMinimumLoggingLevel(Log.DEBUG).build()
+        WorkManagerTestInitHelper.initializeTestWorkManager(mContext, configuration)
+
+        mTestDriver = WorkManagerTestInitHelper.getTestDriver(mContext)!!
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 26)
+    @Throws(InterruptedException::class, ExecutionException::class)
+    fun testScheduledTime_relativeToTestClock() {
+        testClock.timeMillis = Duration.ofDays(100).toMillis()
+        val initialDelay = Duration.ofHours(1)
+
+        val request: WorkRequest =
+            OneTimeWorkRequest.Builder(TestWorker::class.java)
+                .setInitialDelay(initialDelay).build()
+
+        val workManagerImpl = WorkManagerImpl.getInstance(mContext)
+        workManagerImpl.enqueue(listOf(request)).result.get()
+
+        val status = workManagerImpl.getWorkInfoById(request.id).get()
+        assertThat(status.earliestPossibleRuntimeMillis)
+            .isEqualTo(testClock.timeMillis + initialDelay.toMillis())
+    }
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt b/work/work-testing/src/main/java/androidx/work/testing/TestClock.kt
similarity index 63%
copy from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
copy to work/work-testing/src/main/java/androidx/work/testing/TestClock.kt
index f01729c..182b49d 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/InitArg.kt
+++ b/work/work-testing/src/main/java/androidx/work/testing/TestClock.kt
@@ -14,16 +14,19 @@
  * limitations under the License.
  */
 
-package androidx.appactions.interaction.capabilities.core
+package androidx.work.testing
+
+import androidx.annotation.RestrictTo
+import androidx.work.Clock
 
 /**
- * InitArg contains data passed to {@code BaseSession#onInit}.
+ * A settable [Clock] that can be used to control time and precisely test schedules
+ * @suppress
  */
-class InitArg internal constructor() {
-    override fun toString() =
-        "InitArg()"
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class TestClock(var timeMillis: Long) : Clock {
 
-    override fun equals(other: Any?): Boolean {
-        return other is InitArg
+    override fun currentTimeMillis(): Long {
+        return timeMillis
     }
-}
+}
\ No newline at end of file
diff --git a/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt b/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
index 4bccdaa..3a4fa54 100644
--- a/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
+++ b/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
@@ -18,6 +18,7 @@
 
 import androidx.annotation.GuardedBy
 import androidx.annotation.RestrictTo
+import androidx.work.Clock
 import androidx.work.Worker
 import androidx.work.impl.Scheduler
 import androidx.work.impl.StartStopTokens
@@ -37,7 +38,8 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class TestScheduler(
     private val workDatabase: WorkDatabase,
-    private val launcher: WorkLauncher
+    private val launcher: WorkLauncher,
+    private val clock: Clock
 ) : Scheduler, TestDriver {
     @GuardedBy("lock")
     private val pendingWorkStates = mutableMapOf<String, InternalWorkState>()
@@ -62,7 +64,7 @@
         toSchedule.forEach { (spec, state) ->
             // don't even try to run a worker that WorkerWrapper won't execute anyway.
             // similar to logic in WorkerWrapper
-            if (spec.isBackedOff && spec.calculateNextRunTime() > System.currentTimeMillis()) {
+            if (spec.isBackedOff && spec.calculateNextRunTime() > clock.currentTimeMillis()) {
                 return@forEach
             }
             scheduleInternal(spec, state)
@@ -144,7 +146,7 @@
                 pendingWorkStates.remove(generationalId.workSpecId)
                 startStopTokens.tokenFor(generationalId)
             }
-            workDatabase.rewindLastEnqueueTime(spec.id)
+            workDatabase.rewindLastEnqueueTime(spec.id, clock)
             launcher.startWork(token)
         }
     }
@@ -173,17 +175,15 @@
 
 private val WorkSpec.isFirstPeriodicRun get() = periodCount == 0 && runAttemptCount == 0
 
-private fun WorkDatabase.rewindLastEnqueueTime(id: String): WorkSpec {
+private fun WorkDatabase.rewindLastEnqueueTime(id: String, clock: Clock): WorkSpec {
     // We need to pass check that mWorkSpec.calculateNextRunTime() < now
     // so we reset "rewind" enqueue time to pass the check
     // we don't reuse available internalWorkState.mWorkSpec, because it
     // is not update with period_count and last_enqueue_time
-    // More proper solution would be to abstract away time instead of just using
-    // System.currentTimeMillis() in WM
     val dao: WorkSpecDao = workSpecDao()
     val workSpec: WorkSpec = dao.getWorkSpec(id)
         ?: throw IllegalStateException("WorkSpec is already deleted from WM's db")
-    val now = System.currentTimeMillis()
+    val now = clock.currentTimeMillis()
     val timeOffset = workSpec.calculateNextRunTime() - now
     if (timeOffset > 0) {
         dao.setLastEnqueueTime(id, workSpec.lastEnqueueTime - timeOffset)
diff --git a/work/work-testing/src/main/java/androidx/work/testing/TestWorkManagerImpl.kt b/work/work-testing/src/main/java/androidx/work/testing/TestWorkManagerImpl.kt
index a2b86d3..aa1ba31 100644
--- a/work/work-testing/src/main/java/androidx/work/testing/TestWorkManagerImpl.kt
+++ b/work/work-testing/src/main/java/androidx/work/testing/TestWorkManagerImpl.kt
@@ -44,7 +44,8 @@
         context = context,
         configuration = configuration,
         workTaskExecutor = taskExecutor,
-        workDatabase = WorkDatabase.create(context, taskExecutor.serialTaskExecutor, true),
+        workDatabase = WorkDatabase.create(
+            context, taskExecutor.serialTaskExecutor, configuration.clock, true),
         schedulersCreator = ::createTestSchedulers
     )
 }
@@ -58,7 +59,8 @@
         context = context,
         configuration = configuration,
         workTaskExecutor = taskExecutor,
-        workDatabase = WorkDatabase.create(context, taskExecutor.serialTaskExecutor, true),
+        workDatabase = WorkDatabase.create(
+            context, taskExecutor.serialTaskExecutor, configuration.clock, true),
         schedulersCreator = ::createTestSchedulers
     )
 }
@@ -82,5 +84,5 @@
     processor: Processor,
 ): List<Scheduler> {
     val launcher = WorkLauncherImpl(processor, workTaskExecutor)
-    return listOf<Scheduler>(TestScheduler(workDatabase, launcher))
+    return listOf<Scheduler>(TestScheduler(workDatabase, launcher, configuration.clock))
 }
\ No newline at end of file