Merge "Configuration Change Consistency in Play Auth Flow" 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 ba2f6f3..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,7 +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.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
@@ -26,7 +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.ParamProperty
+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
@@ -41,7 +41,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(CreateCall.Property::class.java)
+        .setDescriptor(CreateCall.Properties::class.java)
         .setArguments(CreateCall.Arguments::class.java, CreateCall.Arguments::Builder)
         .setOutput(CreateCall.Output::class.java)
         .bindOptionalParameter(
@@ -74,21 +74,21 @@
 class CreateCall private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<CallFormat>?,
-        val participant: ParamProperty<Participant>?
+        val callFormat: Property<CallFormat>?,
+        val participant: Property<Participant>?
     ) {
         override fun toString(): String {
             return "Property(callFormat=$callFormat, participant=$participant)"
@@ -98,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
@@ -113,15 +113,15 @@
         }
 
         class Builder {
-            private var callFormat: ParamProperty<CallFormat>? = null
+            private var callFormat: Property<CallFormat>? = null
 
-            private var participant: ParamProperty<Participant>? = null
+            private var participant: Property<Participant>? = null
 
-            fun setCallFormat(callFormat: ParamProperty<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)
         }
     }
 
@@ -236,5 +236,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 3399f43..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,7 +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.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,7 +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.ParamProperty
+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
@@ -41,7 +41,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(CreateMessage.Property::class.java)
+        .setDescriptor(CreateMessage.Properties::class.java)
         .setArguments(CreateMessage.Arguments::class.java, CreateMessage.Arguments::Builder)
         .setOutput(CreateMessage.Output::class.java)
         .bindRepeatedParameter(
@@ -74,21 +74,21 @@
 class CreateMessage private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<Recipient>?,
-        val messageText: ParamProperty<StringValue>?
+        val recipient: Property<Recipient>?,
+        val messageText: Property<StringValue>?
     ) {
         override fun toString(): String {
             return "Property(recipient=$recipient, messageText=$messageText)"
@@ -98,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
@@ -113,18 +113,18 @@
         }
 
         class Builder {
-            private var recipient: ParamProperty<Recipient>? = null
-            private var messageText: ParamProperty<StringValue>? = null
+            private var recipient: Property<Recipient>? = null
+            private var messageText: Property<StringValue>? = null
 
-            fun setRecipient(recipient: ParamProperty<Recipient>): Builder = apply {
+            fun setRecipient(recipient: Property<Recipient>): Builder = apply {
                 this.recipient = recipient
             }
 
-            fun setMessageText(messageText: ParamProperty<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)
         }
     }
 
@@ -237,5 +237,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
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 39fee6a..1a917ef 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
@@ -29,5 +29,5 @@
      * @param arguments the argument for this action.
      * @return the ExecutionResult
      */
-    suspend fun execute(arguments: ArgumentsT): ExecutionResult<OutputT>
+    suspend fun onExecute(arguments: ArgumentsT): ExecutionResult<OutputT>
 }
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 e049688..7958e11 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
@@ -32,18 +32,18 @@
      * @param arguments the argument for this action.
      * @return A ListenableFuture containing the ExecutionResult
      */
-    fun execute(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>>
+    fun onExecute(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>>
 
     companion object {
         fun <ArgumentsT, OutputT> ActionExecutor<ArgumentsT, OutputT>.toActionExecutorAsync():
             ActionExecutorAsync<ArgumentsT, OutputT> =
             object : ActionExecutorAsync<ArgumentsT, OutputT> {
                 override val uiHandle = this@toActionExecutorAsync
-                override fun execute(
+                override fun onExecute(
                     arguments: ArgumentsT,
                 ): ListenableFuture<ExecutionResult<OutputT>> =
                     convertToListenableFuture("ActionExecutor#execute") {
-                        [email protected](arguments)
+                        [email protected](arguments)
                     }
             }
     }
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 83%
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 d03b62c..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,8 +20,8 @@
 import androidx.concurrent.futures.await
 import com.google.common.util.concurrent.ListenableFuture
 
-/** Base interface for Session of all verticals. */
-interface BaseSession<ArgumentsT, OutputT> {
+/** Base interface for ExecutionSession of all verticals. */
+interface BaseExecutionSession<ArgumentsT, OutputT> {
     /**
      * Implement any initialization logic.
      *
@@ -35,8 +35,8 @@
      * @param arguments the [ArgumentsT] instance containing data for fulfillment.
      * @return an [ExecutionResult] instance.
      */
-    suspend fun onFinish(arguments: ArgumentsT): ExecutionResult<OutputT> {
-        return onFinishAsync(arguments).await()
+    suspend fun onExecute(arguments: ArgumentsT): ExecutionResult<OutputT> {
+        return onExecuteAsync(arguments).await()
     }
 
     /**
@@ -45,7 +45,7 @@
      * @param arguments the Argument instance containing data for fulfillment.
      * @return a [ListenableFuture] containing an [ExecutionResult] instance.
      */
-    fun onFinishAsync(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>> {
+    fun onExecuteAsync(arguments: ArgumentsT): ListenableFuture<ExecutionResult<OutputT>> {
         return Futures.immediateFuture(ExecutionResult.Builder<OutputT>().build())
     }
 
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 e5f7cd2..fd3a716 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
@@ -66,19 +66,19 @@
             ArgumentsT,
             OutputT,
             ConfirmationT,
-            SessionT,>,
+            ExecutionSessionT,>,
         PropertyT,
         ArgumentsT,
         OutputT,
         ConfirmationT,
-        SessionT : BaseSession<ArgumentsT, OutputT>,
+        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 actionExecutorAsync: ActionExecutorAsync<ArgumentsT, OutputT>? = null
-        private var sessionFactory: SessionFactory<SessionT>? = null
+        private var sessionFactory: ExecutionSessionFactory<ExecutionSessionT>? = null
 
         /**
          * The SessionBridge object, which is used to normalize Session instances to TaskHandler.
@@ -87,7 +87,7 @@
          * @suppress
          */
         @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-        protected open val sessionBridge: SessionBridge<SessionT, ConfirmationT>? = null
+        protected open val sessionBridge: SessionBridge<ExecutionSessionT, ConfirmationT>? = null
 
         @Suppress("UNCHECKED_CAST")
         fun asBuilder(): BuilderT {
@@ -113,8 +113,8 @@
         /**
          * Sets the ActionExecutor for this capability.
          *
-         * setSessionFactory and setExecutor are mutually exclusive, so calling one will nullify
-         * the other.
+         * 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.
@@ -126,8 +126,8 @@
         /**
          * Sets the ActionExecutorAsync for this capability.
          *
-         * setSessionFactory and setExecutor are mutually exclusive, so calling one will nullify
-         * the other.
+         * setExecutionSessionFactory and setExecutor are mutually exclusive, so calling one will
+         * nullify the other.
          *
          * This method accepts the ActionExecutorAsync interface which returns a ListenableFuture.
          */
@@ -141,19 +141,19 @@
          * 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.
+         * [setExecutionSessionFactory] and [setExecutor] are mutually exclusive, so calling one
+         * will nullify the other.
          */
-        protected open fun setSessionFactory(
-            sessionFactory: SessionFactory<SessionT>,
+        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." })
+            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,
@@ -162,14 +162,14 @@
                     actionExecutorAsync!!,
                 )
             } else {
+                val checkedSessionFactory = requireNotNull(sessionFactory) {
+                    "either setExecutor or setExecutionSessionFactory must be called before build"
+                }
                 return TaskCapabilityImpl(
                     checkedId,
                     actionSpec,
                     checkedProperty,
-                    requireNotNull(
-                        sessionFactory,
-                        { "either setExecutor or setSessionFactory must be called before build" },
-                    ),
+                    checkedSessionFactory,
                     sessionBridge!!,
                     ::EmptyTaskUpdater,
                 )
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/SessionContext.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
index 5a6246a9..fd9cbca 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/SessionContext.kt
@@ -17,7 +17,7 @@
 package androidx.appactions.interaction.capabilities.core
 
 /**
- * [SessionContext] contains data passed to {@code BaseSession#onCreate}.
+ * [SessionContext] contains data passed to [BaseExecutionSession.onCreate].
  */
 class SessionContext internal constructor() {
     override fun toString() =
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/SingleTurnCapabilitySession.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilitySession.kt
index 0bb3051..40081e8 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
@@ -75,7 +75,7 @@
             try {
                 mutex.lock(owner = this@SingleTurnCapabilitySession)
                 UiHandleRegistry.registerUiHandle(uiHandle, sessionId)
-                val output = actionExecutorAsync.execute(arguments).await()
+                val output = actionExecutorAsync.onExecute(arguments).await()
                 callback.onSuccess(convertToFulfillmentResponse(output))
             } catch (t: Throwable) {
                 callback.onError(ErrorStatusInternal.CANCELLED)
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 ce31c37..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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.proto.AppActionsContext.IntentParameter;
 import androidx.appactions.interaction.proto.ParamValue;
 
@@ -115,13 +115,13 @@
     }
 
     /**
-     * Binds the parameter name, getter, and setter for a {@link ParamProperty}.
+     * 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 ParamProperty from the property, which must be able to
-     *     fetch a non-null {@code ParamProperty} 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
@@ -132,7 +132,7 @@
             ActionSpecBuilder<PropertyT, ArgumentsT, ArgumentsBuilderT, OutputT> bindParameter(
                     @NonNull String paramName,
                     @NonNull
-                            Function<? super PropertyT, ParamProperty<PossibleValueT>>
+                            Function<? super PropertyT, Property<PossibleValueT>>
                                     propertyGetter,
                     @NonNull BiConsumer<? super ArgumentsBuilderT, T> paramConsumer,
                     @NonNull ParamValueConverter<T> paramValueConverter,
@@ -146,15 +146,15 @@
     }
 
     /**
-     * Binds the parameter name, getter, and setter for a {@link ParamProperty}.
+     * 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 ParamProperty from the property,
-     *     which may be able to fetch a non-null {@code ParamProperty} from {@code PropertyT},
+     * @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
@@ -169,7 +169,7 @@
                             @NonNull
                                     Function<
                                                     ? super PropertyT,
-                                                    Optional<ParamProperty<PossibleValueT>>>
+                                                    Optional<Property<PossibleValueT>>>
                                             optionalPropertyGetter,
                             @NonNull BiConsumer<? super ArgumentsBuilderT, T> paramConsumer,
                             @NonNull ParamValueConverter<T> paramValueConverter,
@@ -206,7 +206,7 @@
                             @NonNull
                                     Function<
                                                     ? super PropertyT,
-                                                    Optional<ParamProperty<PossibleValueT>>>
+                                                    Optional<Property<PossibleValueT>>>
                                             optionalPropertyGetter,
                             @NonNull BiConsumer<? super ArgumentsBuilderT, List<T>> paramConsumer,
                             @NonNull ParamValueConverter<T> paramValueConverter,
@@ -284,11 +284,11 @@
                 mOutputBindings);
     }
 
-    /** Create IntentParameter proto from a ParamProperty. */
+    /** Create IntentParameter proto from a Property. */
     @NonNull
     private static <T> IntentParameter buildIntentParameter(
             @NonNull String paramName,
-            @NonNull ParamProperty<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/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 3d93cf5..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
@@ -16,10 +16,10 @@
 
 package androidx.appactions.interaction.capabilities.core.impl.task
 
-import androidx.appactions.interaction.capabilities.core.BaseSession
+import androidx.appactions.interaction.capabilities.core.BaseExecutionSession
 import androidx.appactions.interaction.capabilities.core.Capability
 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
@@ -29,25 +29,26 @@
 /**
  * @param id a unique id for this capability, can be null
  * @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,
     ArgumentsT,
     OutputT,
-    SessionT : BaseSession<ArgumentsT, OutputT>,
+    ExecutionSessionT : BaseExecutionSession<ArgumentsT, OutputT>,
     ConfirmationT,
-    SessionUpdaterT,
->
+    SessionUpdaterT
+    >
 constructor(
     id: String,
     private val actionSpec: ActionSpec<PropertyT, ArgumentsT, OutputT>,
     private val property: PropertyT,
-    private val sessionFactory: SessionFactory<SessionT>,
-    private val sessionBridge: SessionBridge<SessionT, ConfirmationT>,
-    private val sessionUpdaterSupplier: Supplier<SessionUpdaterT>,
+    private val sessionFactory: ExecutionSessionFactory<ExecutionSessionT>,
+    private val sessionBridge: SessionBridge<ExecutionSessionT, ConfirmationT>,
+    private val sessionUpdaterSupplier: Supplier<SessionUpdaterT>
 ) : Capability(id) {
 
     override val appAction: AppAction =
@@ -60,18 +61,18 @@
 
     override fun createSession(
         sessionId: String,
-        hostProperties: HostProperties,
+        hostProperties: HostProperties
     ): CapabilitySession {
         val externalSession =
             sessionFactory.createSession(
-                hostProperties,
+                hostProperties
             )
         return TaskCapabilitySession(
             sessionId,
             actionSpec,
             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 baf924b..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
@@ -41,7 +41,7 @@
     actionSpec: ActionSpec<*, ArgumentsT, OutputT>,
     appAction: AppAction,
     taskHandler: TaskHandler<ConfirmationT>,
-    externalSession: BaseSession<ArgumentsT, OutputT>,
+    externalSession: BaseExecutionSession<ArgumentsT, OutputT>,
     private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
 ) : CapabilitySession, TaskUpdateHandler {
     override val state: AppDialogState
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 ce81aec..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,7 +16,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.ConfirmationOutput
 import androidx.appactions.interaction.capabilities.core.ExecutionResult
 import androidx.appactions.interaction.capabilities.core.SessionContext
@@ -59,7 +59,7 @@
     private val actionSpec: ActionSpec<*, ArgumentsT, OutputT>,
     private val appAction: AppActionsContext.AppAction,
     private val taskHandler: TaskHandler<ConfirmationT>,
-    private val externalSession: BaseSession<ArgumentsT, 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) ||
@@ -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,7 +449,7 @@
     private suspend fun getFulfillmentResponseForExecution(
         finalArguments: Map<String, List<ParamValue>>,
     ): FulfillmentResponse {
-        val result = externalSession.onFinish(actionSpec.buildArguments(finalArguments))
+        val result = externalSession.onExecute(actionSpec.buildArguments(finalArguments))
         status = CapabilitySession.Status.COMPLETED
         val fulfillmentResponse =
             FulfillmentResponse.newBuilder().setStartDictation(result.shouldStartDictation)
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/Property.kt
similarity index 86%
rename from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/ParamProperty.kt
rename to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/properties/Property.kt
index 262fa73..c338ec9 100644
--- 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/Property.kt
@@ -20,7 +20,7 @@
  * Configure parameters for the capability such as providing possible values of some type, or
  * marking a parameter as required for execution.
  */
-class ParamProperty<T>
+class Property<T>
 internal constructor(
     private val possibleValueSupplier: () -> List<T>,
     /** Indicates that a value for this property is required to be present for fulfillment. */
@@ -40,18 +40,17 @@
      * assistant.
      */
     @get:JvmName("isProhibited")
-    val isProhibited: Boolean,
+    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 ParamProperty}. */
+    /** Builder for {@link Property}. */
     class Builder<T> {
-        private var possibleValueSupplier: () -> List<T> = { emptyList<T>() }
+        private var possibleValueSupplier: () -> List<T> = { emptyList() }
         private var isRequired = false
         private var isValueMatchRequired = false
-        private var isProhibited = false
 
         /**
          * Sets one or more possible values for this parameter.
@@ -82,20 +81,25 @@
             this.isValueMatchRequired = valueMatchRequired
         }
 
-        /**
-         * Sets whether this property is prohibited in the response.
-         *
-         * @param prohibited Whether this property is prohibited in the response.
-         */
-        fun setProhibited(prohibited: Boolean) = apply { this.isProhibited = prohibited }
-
         /** Builds the property for this entity parameter. */
         fun build() =
-            ParamProperty(
+            Property(
                 this.possibleValueSupplier,
                 this.isRequired,
                 this.isValueMatchRequired,
-                this.isProhibited,
+                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/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
index ff0d2ea..b412f34 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/entity/AlarmProvider.kt
@@ -21,10 +21,9 @@
 
 /**  Internal testing object for entity provider */
 class AlarmProvider internal constructor(
-    private var id: String,
+    override val id: String,
     private var response: EntityLookupResponse<Alarm>,
 ) : EntityProvider<Alarm>(TypeConverters.ALARM_TYPE_SPEC) {
-    override fun getId(): String = id
     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/impl/SingleTurnCapabilityTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/SingleTurnCapabilityTest.kt
index 851f343..de130535 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
@@ -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.ParamProperty
+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.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
@@ -70,13 +69,11 @@
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                    Property.newBuilder()
+                Properties.newBuilder()
                         .setRequiredEntityField(
-                            ParamProperty.Builder<Entity>().build(),
+                            Property.Builder<Entity>().build(),
                         )
-                        .setOptionalStringField(
-                            ParamProperty.Builder<StringValue>().setProhibited(true).build(),
-                        )
+                        .setOptionalStringField(Property.prohibited())
                         .build(),
                 actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
             )
@@ -126,13 +123,11 @@
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                    Property.newBuilder()
+                Properties.newBuilder()
                         .setRequiredEntityField(
-                            ParamProperty.Builder<Entity>().build(),
+                            Property.Builder<Entity>().build(),
                         )
-                        .setOptionalStringField(
-                            ParamProperty.Builder<StringValue>().setProhibited(true).build(),
-                        )
+                        .setOptionalStringField(Property.prohibited())
                         .build(),
                 actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
             )
@@ -163,9 +158,9 @@
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                Property.newBuilder()
+                Properties.newBuilder()
                     .setRequiredEntityField(
-                        ParamProperty.Builder<Entity>().build(),
+                        Property.Builder<Entity>().build(),
                     )
                     .build(),
                 actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
@@ -185,9 +180,9 @@
                 id = "capabilityId",
                 actionSpec = ACTION_SPEC,
                 property =
-                Property.newBuilder()
+                Properties.newBuilder()
                     .setRequiredEntityField(
-                        ParamProperty.Builder<Entity>().build(),
+                        Property.Builder<Entity>().build(),
                     )
                     .build(),
                 actionExecutorAsync = actionExecutorAsync,
@@ -209,8 +204,8 @@
         val capability = SingleTurnCapabilityImpl(
             id = "capabilityId",
             actionSpec = ACTION_SPEC,
-            property = Property.newBuilder().setRequiredEntityField(
-                ParamProperty.Builder<Entity>().build(),
+            property = Properties.newBuilder().setRequiredEntityField(
+                Property.Builder<Entity>().build(),
             ).build(),
             actionExecutorAsync = actionExecutor.toActionExecutorAsync(),
         )
@@ -262,16 +257,16 @@
     }
 
     companion object {
-        val ACTION_SPEC: ActionSpec<Property, Arguments, Output> =
+        val ACTION_SPEC: ActionSpec<Properties, Arguments, Output> =
             ActionSpecBuilder.ofCapabilityNamed(
                 "actions.intent.TEST",
             )
-                .setDescriptor(Property::class.java)
+                .setDescriptor(Properties::class.java)
                 .setArguments(Arguments::class.java, Arguments::newBuilder)
                 .setOutput(Output::class.java)
                 .bindOptionalParameter(
                     "optionalString",
-                    Property::optionalStringField,
+                    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/spec/ActionSpecTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
index 261235d..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,7 +24,7 @@
 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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
 import androidx.appactions.interaction.capabilities.core.testing.spec.Output;
 import androidx.appactions.interaction.capabilities.core.values.EntityValue;
@@ -46,44 +46,44 @@
 @RunWith(JUnit4.class)
 public final class ActionSpecTest {
 
-    private static final ActionSpec<Property, Arguments, Output> ACTION_SPEC =
+    private static final ActionSpec<Properties, Arguments, Output> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed("actions.intent.TEST")
-                    .setDescriptor(Property.class)
+                    .setDescriptor(Properties.class)
                     .setArguments(Arguments.class, Arguments::newBuilder)
                     .setOutput(Output.class)
                     .bindParameter(
                             "requiredEntity",
-                            Property::requiredEntityField,
+                            Properties::requiredEntityField,
                             Arguments.Builder::setRequiredEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "optionalEntity",
-                            Property::optionalEntityField,
+                            Properties::optionalEntityField,
                             Arguments.Builder::setOptionalEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindRepeatedParameter(
                             "repeatedEntity",
-                            Property::repeatedEntityField,
+                            Properties::repeatedEntityField,
                             Arguments.Builder::setRepeatedEntityField,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindParameter(
                             "requiredString",
-                            Property::requiredStringField,
+                            Properties::requiredStringField,
                             Arguments.Builder::setRequiredStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "optionalString",
-                            Property::optionalStringField,
+                            Properties::optionalStringField,
                             Arguments.Builder::setOptionalStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindRepeatedParameter(
                             "repeatedString",
-                            Property::repeatedStringField,
+                            Properties::repeatedStringField,
                             Arguments.Builder::setRepeatedStringField,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
@@ -145,17 +145,17 @@
     public void getAppAction_genericParameters() {
         GenericEntityProperty property =
                 GenericEntityProperty.create(
-                        new ParamProperty.Builder<String>()
+                        new Property.Builder<String>()
                                 .setRequired(true)
                                 .setPossibleValues("one")
                                 .build(),
                         Optional.of(
-                                new ParamProperty.Builder<String>()
+                                new Property.Builder<String>()
                                         .setRequired(true)
                                         .setPossibleValues("two")
                                         .build()),
                         Optional.of(
-                                new ParamProperty.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 ParamProperty.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 ParamProperty.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 ParamProperty.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 ParamProperty.Builder<Entity>()
+                                new Property.Builder<Entity>()
                                         .setPossibleValues(
                                                 new Entity.Builder()
                                                         .setId("entity1")
@@ -251,12 +251,12 @@
                                         .setRequired(true)
                                         .build()),
                         Optional.of(
-                                new ParamProperty.Builder<TestEnum>()
+                                new Property.Builder<TestEnum>()
                                         .setPossibleValues(TestEnum.VALUE_1)
                                         .setRequired(true)
                                         .build()),
                         Optional.of(
-                                new ParamProperty.Builder<Entity>()
+                                new Property.Builder<Entity>()
                                         .setPossibleValues(
                                                 new Entity.Builder()
                                                         .setId("entity1")
@@ -268,17 +268,14 @@
                                                         .build())
                                         .setRequired(true)
                                         .build()),
-                        new ParamProperty.Builder<StringValue>().build(),
+                        new Property.Builder<StringValue>().build(),
                         Optional.of(
-                                new ParamProperty.Builder<StringValue>()
+                                new Property.Builder<StringValue>()
                                         .setPossibleValues(StringValue.of("value1"))
                                         .setValueMatchRequired(true)
                                         .setRequired(true)
                                         .build()),
-                        Optional.of(
-                                new ParamProperty.Builder<StringValue>()
-                                        .setProhibited(true)
-                                        .build()));
+                        Optional.of(Property.prohibited()));
 
         assertThat(ACTION_SPEC.convertPropertyToProto(property))
                 .isEqualTo(
@@ -453,17 +450,17 @@
     }
 
     @AutoValue
-    abstract static class Property {
+    abstract static class Properties {
 
-        static Property create(
-                ParamProperty<Entity> requiredEntityField,
-                Optional<ParamProperty<Entity>> optionalEntityField,
-                Optional<ParamProperty<TestEnum>> optionalEnumField,
-                Optional<ParamProperty<Entity>> repeatedEntityField,
-                ParamProperty<StringValue> requiredStringField,
-                Optional<ParamProperty<StringValue>> optionalStringField,
-                Optional<ParamProperty<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(
-                ParamProperty<Entity> requiredEntityField,
-                ParamProperty<StringValue> requiredStringField) {
+        static Properties create(
+                Property<Entity> requiredEntityField,
+                Property<StringValue> requiredStringField) {
             return create(
                     requiredEntityField,
                     Optional.empty(),
@@ -486,19 +483,19 @@
                     Optional.empty());
         }
 
-        abstract ParamProperty<Entity> requiredEntityField();
+        abstract Property<Entity> requiredEntityField();
 
-        abstract Optional<ParamProperty<Entity>> optionalEntityField();
+        abstract Optional<Property<Entity>> optionalEntityField();
 
-        abstract Optional<ParamProperty<TestEnum>> optionalEnumField();
+        abstract Optional<Property<TestEnum>> optionalEnumField();
 
-        abstract Optional<ParamProperty<Entity>> repeatedEntityField();
+        abstract Optional<Property<Entity>> repeatedEntityField();
 
-        abstract ParamProperty<StringValue> requiredStringField();
+        abstract Property<StringValue> requiredStringField();
 
-        abstract Optional<ParamProperty<StringValue>> optionalStringField();
+        abstract Optional<Property<StringValue>> optionalStringField();
 
-        abstract Optional<ParamProperty<StringValue>> repeatedStringField();
+        abstract Optional<Property<StringValue>> repeatedStringField();
     }
 
     @AutoValue
@@ -533,17 +530,17 @@
     abstract static class GenericEntityProperty {
 
         static GenericEntityProperty create(
-                ParamProperty<String> singularField,
-                Optional<ParamProperty<String>> optionalField,
-                Optional<ParamProperty<String>> repeatedField) {
+                Property<String> singularField,
+                Optional<Property<String>> optionalField,
+                Optional<Property<String>> repeatedField) {
             return new AutoValue_ActionSpecTest_GenericEntityProperty(
                     singularField, optionalField, repeatedField);
         }
 
-        abstract ParamProperty<String> singularField();
+        abstract Property<String> singularField();
 
-        abstract Optional<ParamProperty<String>> optionalField();
+        abstract Optional<Property<String>> optionalField();
 
-        abstract Optional<ParamProperty<String>> repeatedField();
+        abstract Optional<Property<String>> repeatedField();
     }
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/ParamPropertyTest.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/ParamPropertyTest.kt
rename to appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/PropertyTest.kt
index 8ca80c8..7563a3f 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/properties/ParamPropertyTest.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 ParamPropertyTest {
+class PropertyTest {
     @Test
     fun dynamicInventory_test() {
         val mutablePossibleValues = mutableListOf<String>("a", "b")
-        val testProperty = ParamProperty.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 e9535c9..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
@@ -20,9 +20,9 @@
 import androidx.appactions.interaction.capabilities.core.Capability
 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.SessionContext
-import androidx.appactions.interaction.capabilities.core.SessionFactory
 import androidx.appactions.interaction.capabilities.core.ValidationResult
 import androidx.appactions.interaction.capabilities.core.ValueListener
 import androidx.appactions.interaction.capabilities.core.impl.CapabilitySession
@@ -37,15 +37,15 @@
 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.ParamProperty
+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
@@ -87,8 +87,8 @@
             SINGLE_REQUIRED_FIELD_PROPERTY,
             sessionFactory =
             {
-                object : Session {
-                    override fun onFinishAsync(arguments: Arguments) =
+                object : ExecutionSession {
+                    override fun onExecuteAsync(arguments: Arguments) =
                         Futures.immediateFuture(ExecutionResult.Builder<Output>().build())
                 }
             },
@@ -122,7 +122,7 @@
 
     @Test
     fun capabilitySession_getUiHandle() {
-        val externalSession = object : Session {}
+        val externalSession = object : ExecutionSession {}
         val capability =
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
@@ -142,12 +142,12 @@
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory =
-                SessionFactory {
-                    object : Session {
+                ExecutionSessionFactory {
+                    object : ExecutionSession {
                         override fun onCreate(sessionContext: SessionContext) {
                             onCreateInvocationCount.incrementAndGet()
                         }
-                        override fun onFinishAsync(arguments: Arguments) =
+                        override fun onExecuteAsync(arguments: Arguments) =
                             Futures.immediateFuture(
                                 ExecutionResult.Builder<Output>().build(),
                             )
@@ -219,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(arguments: Arguments): 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,
         )
@@ -243,12 +243,12 @@
             ),
             callback,
         )
-        onFinishReached.await()
+        onExecuteReached.await()
         assertThat(UiHandleRegistry.getSessionIdFromUiHandle(externalSession)).isEqualTo(
             "mySessionId",
         )
 
-        onFinishResult.complete(ExecutionResult.Builder<Output>().build())
+        onExecuteResult.complete(ExecutionResult.Builder<Output>().build())
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
         assertThat(UiHandleRegistry.getSessionIdFromUiHandle(externalSession)).isNull()
     }
@@ -260,9 +260,9 @@
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory =
-                SessionFactory {
-                    object : Session {
-                        override fun onFinishAsync(arguments: Arguments) =
+                ExecutionSessionFactory {
+                    object : ExecutionSession {
+                        override fun onExecuteAsync(arguments: Arguments) =
                             Futures.immediateFuture(
                                 ExecutionResult.Builder<Output>().build(),
                             )
@@ -296,17 +296,17 @@
 
     @Test
     fun slotFilling_getStatus_smokeTest() {
-        val property: CapabilityTwoEntityValues.Property =
-            CapabilityTwoEntityValues.Property.newBuilder()
+        val property: CapabilityTwoEntityValues.Properties =
+            CapabilityTwoEntityValues.Properties.newBuilder()
                 .setSlotA(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setSlotB(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
@@ -314,15 +314,15 @@
                 )
                 .build()
         val sessionFactory =
-            SessionFactory<CapabilityTwoEntityValues.Session> {
-                object : CapabilityTwoEntityValues.Session {
-                    override suspend fun onFinish(
+            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",
@@ -390,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(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setSlotB(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(false)
@@ -409,18 +409,18 @@
                 )
                 .build()
         val sessionFactory =
-            SessionFactory<CapabilityTwoEntityValues.Session> {
-                object : CapabilityTwoEntityValues.Session {
-                    override suspend fun onFinish(
+            ExecutionSessionFactory<CapabilityTwoEntityValues.ExecutionSession> {
+                object : CapabilityTwoEntityValues.ExecutionSession {
+                    override suspend fun onExecute(
                         arguments: CapabilityTwoEntityValues.Arguments,
                     ): ExecutionResult<Void> {
-                        onFinishInvocationCount.incrementAndGet()
+                        onExecuteInvocationCount.incrementAndGet()
                         return ExecutionResult.Builder<Void>().build()
                     }
                 }
             }
         val sessionBridge =
-            SessionBridge<CapabilityTwoEntityValues.Session, Void> {
+            SessionBridge<CapabilityTwoEntityValues.ExecutionSession, Void> {
                 TaskHandler.Builder<Void>()
                     .registerValueTaskParam(
                         "slotA",
@@ -458,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()
@@ -482,17 +482,17 @@
     @Test
     @kotlin.Throws(Exception::class)
     fun slotFilling_assistantRemovedParam_clearInSdkState() {
-        val property: Property =
-            Property.newBuilder()
+        val property: Properties =
+            Properties.newBuilder()
                 .setRequiredEntityField(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
                         .build(),
                 )
                 .setEnumField(
-                    ParamProperty.Builder<TestEnum>()
+                    Property.Builder<TestEnum>()
                         .setPossibleValues(TestEnum.VALUE_1, TestEnum.VALUE_2)
                         .setRequired(true)
                         .build(),
@@ -501,7 +501,7 @@
         val capability: Capability =
             createCapability(
                 property,
-                sessionFactory = SessionFactory { Session.DEFAULT },
+                sessionFactory = ExecutionSessionFactory { ExecutionSession.DEFAULT },
                 sessionBridge = SessionBridge { TaskHandler.Builder<Confirmation>().build() },
                 sessionUpdaterSupplier = ::EmptyTaskUpdater,
             )
@@ -560,8 +560,8 @@
             createCapability(
                 SINGLE_REQUIRED_FIELD_PROPERTY,
                 sessionFactory = {
-                    object : Session {
-                        override suspend fun onFinish(arguments: Arguments) =
+                    object : ExecutionSession {
+                        override suspend fun onExecute(arguments: Arguments) =
                             ExecutionResult.Builder<Output>().build()
 
                         override fun getRequiredEntityListener() =
@@ -587,7 +587,7 @@
                     }
                 },
                 sessionBridge =
-                SessionBridge<Session, Confirmation> { session ->
+                SessionBridge<ExecutionSession, Confirmation> { session ->
                     val builder = TaskHandler.Builder<Confirmation>()
                     session.getRequiredEntityListener()
                         ?.let { listener: AppEntityListener<EntityValue> ->
@@ -698,27 +698,27 @@
     @kotlin.Throws(Exception::class)
     @Suppress("DEPRECATION") // TODO(b/269638788) migrate session state to AppDialogState message
     fun identifierOnly_refillsStruct() = runBlocking<Unit> {
-        val property: CapabilityStructFill.Property =
-            CapabilityStructFill.Property.newBuilder()
-                .setListItem(ParamProperty.Builder<ListItem>().setRequired(true).build())
-                .setAnyString(ParamProperty.Builder<StringValue>().setRequired(true).build())
+        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 onReceivedDeferred = CompletableDeferred<ListItem>()
-        val onFinishListItemDeferred = CompletableDeferred<ListItem>()
-        val onFinishStringDeferred = CompletableDeferred<String>()
+        val onExecuteListItemDeferred = CompletableDeferred<ListItem>()
+        val onExecuteStringDeferred = CompletableDeferred<String>()
 
         val sessionFactory =
-            SessionFactory<CapabilityStructFill.Session> {
-                object : CapabilityStructFill.Session {
-                    override suspend fun onFinish(
+            ExecutionSessionFactory<CapabilityStructFill.ExecutionSession> {
+                object : CapabilityStructFill.ExecutionSession {
+                    override suspend fun onExecute(
                         arguments: CapabilityStructFill.Arguments,
                     ): ExecutionResult<Void> {
                         val listItem: ListItem = arguments.listItem().orElse(null)
                         val string: String = arguments.anyString().orElse(null)
-                        onFinishListItemDeferred.complete(listItem)
-                        onFinishStringDeferred.complete(string)
+                        onExecuteListItemDeferred.complete(listItem)
+                        onExecuteStringDeferred.complete(string)
                         return ExecutionResult.Builder<Void>().build()
                     }
 
@@ -744,7 +744,7 @@
                 }
             }
         val sessionBridge =
-            SessionBridge<CapabilityStructFill.Session, Void> { session ->
+            SessionBridge<CapabilityStructFill.ExecutionSession, Void> { session ->
                 TaskHandler.Builder<Void>()
                     .registerAppEntityTaskParam(
                         "listItem",
@@ -775,7 +775,7 @@
         )
         assertThat(callback.receiveResponse().fulfillmentResponse).isNotNull()
         assertThat(onReceivedDeferred.isCompleted).isFalse()
-        assertThat(onFinishListItemDeferred.isCompleted).isFalse()
+        assertThat(onExecuteListItemDeferred.isCompleted).isFalse()
         assertThat(session.state)
             .isEqualTo(
                 AppDialogState.newBuilder()
@@ -823,7 +823,7 @@
         )
         assertThat(callback2.receiveResponse().fulfillmentResponse).isNotNull()
         assertThat(onReceivedDeferred.awaitSync()).isEqualTo(item2)
-        assertThat(onFinishListItemDeferred.isCompleted).isFalse()
+        assertThat(onExecuteListItemDeferred.isCompleted).isFalse()
 
         // third sync request, sending grounded ParamValue with identifier only, completes task
         val callback3 = FakeCallbackInternal()
@@ -838,17 +838,17 @@
             callback3,
         )
         assertThat(callback3.receiveResponse().fulfillmentResponse).isNotNull()
-        assertThat(onFinishListItemDeferred.awaitSync()).isEqualTo(item2)
-        assertThat(onFinishStringDeferred.awaitSync()).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(arguments: Arguments) =
+            ExecutionSessionFactory<ExecutionSession> {
+                object : ExecutionSession {
+                    override suspend fun onExecute(arguments: Arguments) =
                         ExecutionResult.Builder<Output>()
                             .setOutput(
                                 Output.builder()
@@ -862,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 =
@@ -908,16 +908,16 @@
     @kotlin.Throws(Exception::class)
     fun executionResult_shouldStartDictation_resultReturned() {
         val sessionFactory =
-            SessionFactory<Session> {
-                object : Session {
-                    override suspend fun onFinish(arguments: Arguments) =
+            ExecutionSessionFactory<ExecutionSession> {
+                object : ExecutionSession {
+                    override suspend fun onExecute(arguments: Arguments) =
                         ExecutionResult.Builder<Output>()
                             .setStartDictation(true)
                             .build()
                 }
             }
         val capability =
-            CapabilityBuilder().setId("fakeId").setSessionFactory(sessionFactory).build()
+            CapabilityBuilder().setId("fakeId").setExecutionSessionFactory(sessionFactory).build()
         val session = capability.createSession(fakeSessionId, hostProperties)
         val callback = FakeCallbackInternal()
 
@@ -940,24 +940,24 @@
     class CapabilityBuilder :
         Capability.Builder<
             CapabilityBuilder,
-            Property,
+            Properties,
             Arguments,
             Output,
             Confirmation,
-            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()
         }
 
-        public override fun setSessionFactory(
-            sessionFactory: SessionFactory<Session>,
-        ): CapabilityBuilder = super.setSessionFactory(sessionFactory)
+        public override fun setExecutionSessionFactory(
+            sessionFactory: ExecutionSessionFactory<ExecutionSession>,
+        ): CapabilityBuilder = super.setExecutionSessionFactory(sessionFactory)
     }
 
     companion object {
@@ -1014,37 +1014,37 @@
                     return ParamValue.newBuilder().build()
                 }
             }
-        private val ACTION_SPEC: ActionSpec<Property, Arguments, Output> =
+        private val ACTION_SPEC: ActionSpec<Properties, Arguments, Output> =
             ActionSpecBuilder.ofCapabilityNamed(
                 CAPABILITY_NAME,
             )
-                .setDescriptor(Property::class.java)
+                .setDescriptor(Properties::class.java)
                 .setArguments(Arguments::class.java, Arguments::newBuilder)
                 .setOutput(Output::class.java)
                 .bindParameter(
                     "required",
-                    Property::requiredEntityField,
+                    Properties::requiredEntityField,
                     Arguments.Builder::setRequiredEntityField,
                     TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                     TypeConverters.ENTITY_ENTITY_CONVERTER,
                 )
                 .bindOptionalParameter(
                     "optional",
-                    Property::optionalStringField,
+                    Properties::optionalStringField,
                     Arguments.Builder::setOptionalStringField,
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
                 )
                 .bindOptionalParameter(
                     "optionalEnum",
-                    Property::enumField,
+                    Properties::enumField,
                     Arguments.Builder::setEnumField,
                     ENUM_CONVERTER,
                     { Entity.newBuilder().setIdentifier(it.toString()).build() },
                 )
                 .bindRepeatedParameter(
                     "repeated",
-                    Property::repeatedStringField,
+                    Properties::repeatedStringField,
                     Arguments.Builder::setRepeatedStringField,
                     TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                     TypeConverters.STRING_VALUE_ENTITY_CONVERTER,
@@ -1061,10 +1061,10 @@
                 )
                 .build()
 
-        private val SINGLE_REQUIRED_FIELD_PROPERTY: Property =
-            Property.newBuilder()
+        private val SINGLE_REQUIRED_FIELD_PROPERTY: Properties =
+            Properties.newBuilder()
                 .setRequiredEntityField(
-                    ParamProperty.Builder<
+                    Property.Builder<
                         androidx.appactions.interaction.capabilities.core.properties.Entity,
                         >()
                         .setRequired(true)
@@ -1090,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,
+            Properties,
             Arguments,
             Output,
-            Session,
+            ExecutionSession,
             Confirmation,
             SessionUpdaterT,
             > {
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 0b0962c..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,14 +20,14 @@
 
 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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
 import androidx.appactions.interaction.capabilities.core.values.ListItem;
 
@@ -39,19 +39,19 @@
 public final class CapabilityStructFill {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Arguments, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
+                    .setDescriptor(Properties.class)
                     .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "listItem",
-                            Property::listItem,
+                            Properties::listItem,
                             Arguments.Builder::setListItem,
                             ParamValueConverter.Companion.of(LIST_ITEM_TYPE_SPEC),
                             EntityConverter.Companion.of(LIST_ITEM_TYPE_SPEC)::convert)
                     .bindOptionalParameter(
                             "string",
-                            Property::anyString,
+                            Properties::anyString,
                             Arguments.Builder::setAnyString,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
@@ -86,32 +86,32 @@
 
     /** 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<ParamProperty<ListItem>> listItem();
+        public abstract Optional<Property<ListItem>> listItem();
 
-        public abstract Optional<ParamProperty<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 ParamProperty<ListItem> value);
+            public abstract Builder setListItem(@NonNull Property<ListItem> value);
 
             @NonNull
-            public abstract Builder setAnyString(@NonNull ParamProperty<StringValue> value);
+            public abstract Builder setAnyString(@NonNull Property<StringValue> value);
 
             @NonNull
-            public abstract Property build();
+            public abstract Properties build();
         }
     }
 
-    public interface Session extends BaseSession<Arguments, 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 3e54c8a..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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.values.EntityValue;
 
 import com.google.auto.value.AutoValue;
@@ -33,19 +33,19 @@
 public final class CapabilityTwoEntityValues {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Arguments, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
+                    .setDescriptor(Properties.class)
                     .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "slotA",
-                            Property::slotA,
+                            Properties::slotA,
                             Arguments.Builder::setSlotA,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "slotB",
-                            Property::slotB,
+                            Properties::slotB,
                             Arguments.Builder::setSlotB,
                             TypeConverters.ENTITY_PARAM_VALUE_CONVERTER,
                             TypeConverters.ENTITY_ENTITY_CONVERTER)
@@ -79,30 +79,30 @@
 
     /** 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<ParamProperty<Entity>> slotA();
+        public abstract Optional<Property<Entity>> slotA();
 
-        public abstract Optional<ParamProperty<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 ParamProperty<Entity> value);
+            public abstract Builder setSlotA(@NonNull Property<Entity> value);
 
             @NonNull
-            public abstract Builder setSlotB(@NonNull ParamProperty<Entity> value);
+            public abstract Builder setSlotB(@NonNull Property<Entity> value);
 
             @NonNull
-            public abstract Property build();
+            public abstract Properties build();
         }
     }
 
-    public interface Session extends BaseSession<Arguments, 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 1c0eaad..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,7 +21,7 @@
 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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
 
 import com.google.auto.value.AutoValue;
@@ -31,19 +31,19 @@
 public final class CapabilityTwoStrings {
 
     private static final String CAPABILITY_NAME = "actions.intent.TEST";
-    public static final ActionSpec<Property, Arguments, Void> ACTION_SPEC =
+    public static final ActionSpec<Properties, Arguments, Void> ACTION_SPEC =
             ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-                    .setDescriptor(Property.class)
+                    .setDescriptor(Properties.class)
                     .setArguments(Arguments.class, Arguments::newBuilder)
                     .bindOptionalParameter(
                             "stringSlotA",
-                            Property::stringSlotA,
+                            Properties::stringSlotA,
                             Arguments.Builder::setStringSlotA,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
                     .bindOptionalParameter(
                             "stringSlotB",
-                            Property::stringSlotB,
+                            Properties::stringSlotB,
                             Arguments.Builder::setStringSlotB,
                             TypeConverters.STRING_PARAM_VALUE_CONVERTER,
                             TypeConverters.STRING_VALUE_ENTITY_CONVERTER)
@@ -79,28 +79,28 @@
 
     /** 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<ParamProperty<StringValue>> stringSlotA();
+        public abstract Optional<Property<StringValue>> stringSlotA();
 
-        public abstract Optional<ParamProperty<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 ParamProperty<StringValue> value);
+            public abstract Builder setStringSlotA(@NonNull Property<StringValue> value);
 
             @NonNull
-            public abstract Builder setStringSlotB(@NonNull ParamProperty<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 82%
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 cfebbd5..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,19 +17,19 @@
 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<Arguments, Output> {
+interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
 
     fun getRequiredEntityListener(): AppEntityListener<EntityValue>? = null
 
     companion object {
         @JvmStatic
-        val DEFAULT: Session = object : Session {
-            override fun onFinishAsync(arguments: Arguments) =
+        val DEFAULT = object : ExecutionSession {
+            override fun onExecuteAsync(arguments: Arguments) =
                 Futures.immediateFuture(
                     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 65f5bf3..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,7 +19,7 @@
 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.ParamProperty;
+import androidx.appactions.interaction.capabilities.core.properties.Property;
 import androidx.appactions.interaction.capabilities.core.properties.StringValue;
 
 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 ParamProperty<Entity> requiredEntityField();
+    public abstract Property<Entity> requiredEntityField();
 
-    public abstract Optional<ParamProperty<StringValue>> optionalStringField();
+    public abstract Optional<Property<StringValue>> optionalStringField();
 
-    public abstract Optional<ParamProperty<TestEnum>> enumField();
+    public abstract Optional<Property<TestEnum>> enumField();
 
-    public abstract Optional<ParamProperty<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(ParamProperty<Entity> property);
+        public abstract Builder setRequiredEntityField(Property<Entity> property);
 
-        public abstract Builder setOptionalStringField(ParamProperty<StringValue> property);
+        public abstract Builder setOptionalStringField(Property<StringValue> property);
 
-        public abstract Builder setEnumField(ParamProperty<TestEnum> property);
+        public abstract Builder setEnumField(Property<TestEnum> property);
 
-        public abstract Builder setRepeatedStringField(ParamProperty<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 92cb50e..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
@@ -17,12 +17,12 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.LocalTime
 import java.util.Optional
 
@@ -32,7 +32,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(GetExerciseObservation.Property::class.java)
+        .setDescriptor(GetExerciseObservation.Properties::class.java)
         .setArguments(
             GetExerciseObservation.Arguments::class.java,
             GetExerciseObservation.Arguments::Builder
@@ -58,14 +58,14 @@
 class GetExerciseObservation private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setStartTimeProperty(startTime: ParamProperty<LocalTime>): CapabilityBuilder = apply {
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(startTime)
         }
 
-        fun setEndTimeProperty(endTime: ParamProperty<LocalTime>): CapabilityBuilder = apply {
+        fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(endTime)
         }
 
@@ -77,9 +77,9 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val startTime: ParamProperty<LocalTime>?,
-        val endTime: ParamProperty<LocalTime>?
+    class Properties internal constructor(
+        val startTime: Property<LocalTime>?,
+        val endTime: Property<LocalTime>?
     ) {
         override fun toString(): String {
             return "Property(startTime=$startTime, endTime=$endTime)"
@@ -89,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
@@ -104,16 +104,16 @@
         }
 
         class Builder {
-            private var startTime: ParamProperty<LocalTime>? = null
-            private var endTime: ParamProperty<LocalTime>? = null
+            private var startTime: Property<LocalTime>? = null
+            private var endTime: Property<LocalTime>? = null
 
-            fun setStartTime(startTime: ParamProperty<LocalTime>): Builder =
+            fun setStartTime(startTime: Property<LocalTime>): Builder =
                 apply { this.startTime = startTime }
 
-            fun setEndTime(endTime: ParamProperty<LocalTime>): Builder =
+            fun setEndTime(endTime: Property<LocalTime>): Builder =
                 apply { this.endTime = endTime }
 
-            fun build(): Property = Property(startTime, endTime)
+            fun build(): Properties = Properties(startTime, endTime)
         }
     }
 
@@ -161,5 +161,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 64132f2..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
@@ -17,12 +17,12 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.LocalTime
 import java.util.Optional
 
@@ -32,7 +32,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(GetHealthObservation.Property::class.java)
+        .setDescriptor(GetHealthObservation.Properties::class.java)
         .setArguments(
             GetHealthObservation.Arguments::class.java,
             GetHealthObservation.Arguments::Builder
@@ -58,14 +58,14 @@
 class GetHealthObservation private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setStartTimeProperty(startTime: ParamProperty<LocalTime>): CapabilityBuilder = apply {
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setStartTimeProperty(startTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(startTime)
         }
 
-        fun setEndTimeProperty(endTime: ParamProperty<LocalTime>): CapabilityBuilder = apply {
+        fun setEndTimeProperty(endTime: Property<LocalTime>): CapabilityBuilder = apply {
             propertyBuilder.setEndTime(endTime)
         }
 
@@ -77,9 +77,9 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val startTime: ParamProperty<LocalTime>?,
-        val endTime: ParamProperty<LocalTime>?
+    class Properties internal constructor(
+        val startTime: Property<LocalTime>?,
+        val endTime: Property<LocalTime>?
     ) {
         override fun toString(): String {
             return "Property(startTime=$startTime, endTime=$endTime)"
@@ -89,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
@@ -104,16 +104,16 @@
         }
 
         class Builder {
-            private var startTime: ParamProperty<LocalTime>? = null
-            private var endTime: ParamProperty<LocalTime>? = null
+            private var startTime: Property<LocalTime>? = null
+            private var endTime: Property<LocalTime>? = null
 
-            fun setStartTime(startTime: ParamProperty<LocalTime>): Builder =
+            fun setStartTime(startTime: Property<LocalTime>): Builder =
                 apply { this.startTime = startTime }
 
-            fun setEndTime(endTime: ParamProperty<LocalTime>): Builder =
+            fun setEndTime(endTime: Property<LocalTime>): Builder =
                 apply { this.endTime = endTime }
 
-            fun build(): Property = Property(startTime, endTime)
+            fun build(): Properties = Properties(startTime, endTime)
         }
     }
 
@@ -161,5 +161,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 6317e4e..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
@@ -17,13 +17,13 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.util.Optional
 
 /** PauseExercise.kt in interaction-capabilities-fitness */
@@ -32,7 +32,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(PauseExercise.Property::class.java)
+        .setDescriptor(PauseExercise.Properties::class.java)
         .setArguments(PauseExercise.Arguments::class.java, PauseExercise.Arguments::Builder)
         .setOutput(PauseExercise.Output::class.java)
         .bindOptionalParameter(
@@ -48,10 +48,10 @@
 class PauseExercise private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: ParamProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -64,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: ParamProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -75,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
 
@@ -87,12 +87,12 @@
         }
 
         class Builder {
-            private var name: ParamProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: ParamProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
@@ -132,5 +132,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 a0694b8..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
@@ -17,13 +17,13 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.util.Optional
 
 /** ResumeExercise.kt in interaction-capabilities-fitness */
@@ -32,7 +32,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResumeExercise.Property::class.java)
+        .setDescriptor(ResumeExercise.Properties::class.java)
         .setArguments(ResumeExercise.Arguments::class.java, ResumeExercise.Arguments::Builder)
         .setOutput(ResumeExercise.Output::class.java)
         .bindOptionalParameter(
@@ -48,10 +48,10 @@
 class ResumeExercise private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: ParamProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -64,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: ParamProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -75,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
 
@@ -87,12 +87,12 @@
         }
 
         class Builder {
-            private var name: ParamProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: ParamProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
@@ -132,5 +132,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 a844a88..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
@@ -17,13 +17,13 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import java.time.Duration
 import java.util.Optional
 
@@ -33,7 +33,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartExercise.Property::class.java)
+        .setDescriptor(StartExercise.Properties::class.java)
         .setArguments(StartExercise.Arguments::class.java, StartExercise.Arguments::Builder)
         .setOutput(StartExercise.Output::class.java)
         .bindOptionalParameter(
@@ -56,29 +56,29 @@
 class StartExercise private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        fun setDurationProperty(duration: ParamProperty<Duration>): CapabilityBuilder =
+        fun setDurationProperty(duration: Property<Duration>): CapabilityBuilder =
             apply {
-                Property.Builder().setDuration(duration).build()
+                Properties.Builder().setDuration(duration).build()
             }
 
-        fun setNameProperty(name: ParamProperty<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: ParamProperty<Duration>?,
-        val name: ParamProperty<StringValue>?
+    class Properties internal constructor(
+        val duration: Property<Duration>?,
+        val name: Property<StringValue>?
     ) {
         override fun toString(): String {
             return "Property(duration=$duration, name=$name)"
@@ -88,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
@@ -103,16 +103,16 @@
         }
 
         class Builder {
-            private var duration: ParamProperty<Duration>? = null
-            private var name: ParamProperty<StringValue>? = null
+            private var duration: Property<Duration>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setDuration(duration: ParamProperty<Duration>): Builder =
+            fun setDuration(duration: Property<Duration>): Builder =
                 apply { this.duration = duration }
 
-            fun setName(name: ParamProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(duration, name)
+            fun build(): Properties = Properties(duration, name)
         }
     }
 
@@ -160,5 +160,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 dbcd89f..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
@@ -17,12 +17,12 @@
 package androidx.appactions.interaction.capabilities.fitness.fitness
 
 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.ParamProperty
+import androidx.appactions.interaction.capabilities.core.properties.Property
 import androidx.appactions.interaction.capabilities.core.properties.StringValue
 import java.util.Optional
 
@@ -32,7 +32,7 @@
 // TODO(b/273602015): Update to use Name property from builtintype library.
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopExercise.Property::class.java)
+        .setDescriptor(StopExercise.Properties::class.java)
         .setArguments(StopExercise.Arguments::class.java, StopExercise.Arguments::Builder)
         .setOutput(StopExercise.Output::class.java)
         .bindOptionalParameter(
@@ -48,10 +48,10 @@
 class StopExercise private constructor() {
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession
             >(ACTION_SPEC) {
-        private var propertyBuilder: Property.Builder = Property.Builder()
-        fun setNameProperty(name: ParamProperty<StringValue>): CapabilityBuilder =
+        private var propertyBuilder: Properties.Builder = Properties.Builder()
+        fun setNameProperty(name: Property<StringValue>): CapabilityBuilder =
             apply {
                 propertyBuilder.setName(name)
             }
@@ -64,8 +64,8 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property internal constructor(
-        val name: ParamProperty<StringValue>?,
+    class Properties internal constructor(
+        val name: Property<StringValue>?,
     ) {
         override fun toString(): String {
             return "Property(name=$name)"
@@ -75,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
 
@@ -87,12 +87,12 @@
         }
 
         class Builder {
-            private var name: ParamProperty<StringValue>? = null
+            private var name: Property<StringValue>? = null
 
-            fun setName(name: ParamProperty<StringValue>): Builder =
+            fun setName(name: Property<StringValue>): Builder =
                 apply { this.name = name }
 
-            fun build(): Property = Property(name)
+            fun build(): Properties = Properties(name)
         }
     }
 
@@ -132,5 +132,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 7f88a05..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,11 +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.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.ParamProperty
+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
@@ -34,7 +34,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(PauseTimer.Property::class.java)
+        .setDescriptor(PauseTimer.Properties::class.java)
         .setArguments(PauseTimer.Arguments::class.java, PauseTimer.Arguments::Builder)
         .setOutput(PauseTimer.Output::class.java)
         .bindRepeatedParameter(
@@ -57,22 +57,22 @@
     class CapabilityBuilder :
         Capability.Builder<
             CapabilityBuilder,
-            Property,
+            Properties,
             Arguments,
             Output,
             Confirmation,
-            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: ParamProperty<TimerValue>?,
+        val timerList: Property<TimerValue>?,
     ) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
@@ -82,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
 
@@ -94,13 +94,13 @@
         }
 
         class Builder {
-            private var timerList: ParamProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: ParamProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
@@ -200,5 +200,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 4bb0fb1..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,11 +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.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.ParamProperty
+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
@@ -34,7 +34,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResetTimer.Property::class.java)
+        .setDescriptor(ResetTimer.Properties::class.java)
         .setArguments(ResetTimer.Arguments::class.java, ResetTimer.Arguments::Builder)
         .setOutput(ResetTimer.Output::class.java)
         .bindRepeatedParameter(
@@ -56,16 +56,16 @@
 
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -74,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
 
@@ -86,13 +86,13 @@
         }
 
         class Builder {
-            private var timerList: ParamProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: ParamProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
@@ -189,5 +189,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 63931d9..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,11 +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.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.ParamProperty
+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
@@ -34,7 +34,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(ResumeTimer.Property::class.java)
+        .setDescriptor(ResumeTimer.Properties::class.java)
         .setArguments(ResumeTimer.Arguments::class.java, ResumeTimer.Arguments::Builder)
         .setOutput(ResumeTimer.Output::class.java)
         .bindRepeatedParameter(
@@ -56,16 +56,16 @@
 
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -74,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
 
@@ -86,13 +86,13 @@
         }
 
         class Builder {
-            private var timerList: ParamProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: ParamProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
@@ -189,5 +189,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 0878ed0..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,14 +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.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.ParamProperty
+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
@@ -40,7 +40,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartTimer.Property::class.java)
+        .setDescriptor(StartTimer.Properties::class.java)
         .setArguments(StartTimer.Arguments::class.java, StartTimer.Arguments::Builder)
         .setOutput(StartTimer.Output::class.java)
         .bindOptionalParameter(
@@ -71,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 {
@@ -96,22 +96,22 @@
 
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session,
+            CapabilityBuilder, Properties, Arguments, Output, Confirmation, ExecutionSession,
             >(ACTION_SPEC) {
 
-        override val sessionBridge: SessionBridge<Session, Confirmation> = SESSION_BRIDGE
+        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<Arguments, Output> {
+    interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
         val nameListener: ValueListener<String>?
             get() = null
         val durationListener: ValueListener<Duration>?
@@ -119,11 +119,11 @@
     }
 
     // TODO(b/268369632): Remove Property from public capability APIs.
-    class Property
+    class Properties
     internal constructor(
-        val identifier: ParamProperty<StringValue>?,
-        val name: ParamProperty<StringValue>?,
-        val duration: ParamProperty<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}"
@@ -133,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
@@ -150,21 +150,21 @@
         }
 
         class Builder {
-            private var identifier: ParamProperty<StringValue>? = null
-            private var name: ParamProperty<StringValue>? = null
-            private var duration: ParamProperty<Duration>? = null
+            private var identifier: Property<StringValue>? = null
+            private var name: Property<StringValue>? = null
+            private var duration: Property<Duration>? = null
 
-            fun setIdentifier(identifier: ParamProperty<StringValue>): Builder = apply {
+            fun setIdentifier(identifier: Property<StringValue>): Builder = apply {
                 this.identifier = identifier
             }
 
-            fun setName(name: ParamProperty<StringValue>): Builder = apply { this.name = name }
+            fun setName(name: Property<StringValue>): Builder = apply { this.name = name }
 
-            fun setDuration(duration: ParamProperty<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)
         }
     }
 
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 1b1e866..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,11 +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.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.ParamProperty
+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
@@ -34,7 +34,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopTimer.Property::class.java)
+        .setDescriptor(StopTimer.Properties::class.java)
         .setArguments(StopTimer.Arguments::class.java, StopTimer.Arguments::Builder)
         .setOutput(StopTimer.Output::class.java)
         .bindRepeatedParameter(
@@ -56,16 +56,16 @@
 
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<TimerValue>?) {
+    class Properties internal constructor(val timerList: Property<TimerValue>?) {
         override fun toString(): String {
             return "Property(timerList=$timerList}"
         }
@@ -74,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
 
@@ -86,13 +86,13 @@
         }
 
         class Builder {
-            private var timerList: ParamProperty<TimerValue>? = null
+            private var timerList: Property<TimerValue>? = null
 
-            fun setTimerList(timerList: ParamProperty<TimerValue>): Builder = apply {
+            fun setTimerList(timerList: Property<TimerValue>): Builder = apply {
                 this.timerList = timerList
             }
 
-            fun build(): Property = Property(timerList)
+            fun build(): Properties = Properties(timerList)
         }
     }
 
@@ -189,5 +189,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 52c143c..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
@@ -17,7 +17,7 @@
 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.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
@@ -37,7 +37,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartEmergencySharing.Property::class.java)
+        .setDescriptor(StartEmergencySharing.Properties::class.java)
         .setArguments(
             StartEmergencySharing.Arguments::class.java,
             StartEmergencySharing.Arguments::Builder
@@ -55,16 +55,16 @@
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session,
+            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 Arguments internal constructor() {
         class Builder : BuilderOf<Arguments> {
@@ -167,5 +167,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 674de44..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,13 +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.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.ParamProperty
+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
@@ -44,7 +44,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StartSafetyCheck.Property::class.java)
+        .setDescriptor(StartSafetyCheck.Properties::class.java)
         .setArguments(StartSafetyCheck.Arguments::class.java, StartSafetyCheck.Arguments::Builder)
         .setOutput(StartSafetyCheck.Output::class.java)
         .bindOptionalParameter(
@@ -78,19 +78,19 @@
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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: ParamProperty<Duration>?,
-        val checkInTime: ParamProperty<ZonedDateTime>?
+    class Properties internal constructor(
+        val duration: Property<Duration>?,
+        val checkInTime: Property<ZonedDateTime>?
     ) {
         override fun toString(): String {
             return "Property(duration=$duration, checkInTime=$checkInTime)"
@@ -100,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
@@ -115,17 +115,17 @@
         }
 
         class Builder {
-            private var duration: ParamProperty<Duration>? = null
+            private var duration: Property<Duration>? = null
 
-            private var checkInTime: ParamProperty<ZonedDateTime>? = null
+            private var checkInTime: Property<ZonedDateTime>? = null
 
-            fun setDuration(duration: ParamProperty<Duration>): Builder =
+            fun setDuration(duration: Property<Duration>): Builder =
                 apply { this.duration = duration }
 
-            fun setCheckInTime(checkInTime: ParamProperty<ZonedDateTime>): Builder =
+            fun setCheckInTime(checkInTime: Property<ZonedDateTime>): Builder =
                 apply { this.checkInTime = checkInTime }
 
-            fun build(): Property = Property(duration, checkInTime)
+            fun build(): Properties = Properties(duration, checkInTime)
         }
     }
 
@@ -284,5 +284,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 56278e6..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
@@ -17,7 +17,7 @@
 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.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
@@ -37,7 +37,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopEmergencySharing.Property::class.java)
+        .setDescriptor(StopEmergencySharing.Properties::class.java)
         .setArguments(
             StopEmergencySharing.Arguments::class.java,
             StopEmergencySharing.Arguments::Builder
@@ -55,16 +55,16 @@
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session,
+            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 Arguments internal constructor() {
         class Builder : BuilderOf<Arguments> {
@@ -167,5 +167,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, 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 f1c87ea..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
@@ -17,7 +17,7 @@
 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.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
@@ -37,7 +37,7 @@
 
 private val ACTION_SPEC =
     ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-        .setDescriptor(StopSafetyCheck.Property::class.java)
+        .setDescriptor(StopSafetyCheck.Properties::class.java)
         .setArguments(StopSafetyCheck.Arguments::class.java, StopSafetyCheck.Arguments::Builder)
         .setOutput(StopSafetyCheck.Output::class.java)
         .bindOptionalOutput(
@@ -52,16 +52,16 @@
     // TODO(b/267805819): Update to include the SessionFactory once Session API is ready.
     class CapabilityBuilder :
         Capability.Builder<
-            CapabilityBuilder, Property, Arguments, Output, Confirmation, Session
+            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 Arguments internal constructor() {
         class Builder : BuilderOf<Arguments> {
@@ -164,5 +164,5 @@
 
     class Confirmation internal constructor()
 
-    sealed interface Session : BaseSession<Arguments, Output>
+    sealed interface ExecutionSession : BaseExecutionSession<Arguments, Output>
 }
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 c6f6562..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,7 +98,8 @@
                     .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() {
@@ -111,13 +108,17 @@
         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 6a2737c..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
@@ -33,7 +33,7 @@
 import androidx.appactions.interaction.service.testing.internal.FakeCapability
 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,9 +104,9 @@
         UiSessions.removeUiCache(sessionId)
     }
 
-    fun createFakeSessionWithUiResponses(vararg uiResponses: UiResponse): Session {
-        return object : Session {
-            override suspend fun onFinish(
+    fun createFakeSessionWithUiResponses(vararg uiResponses: UiResponse): ExecutionSession {
+        return object : ExecutionSession {
+            override suspend fun onExecute(
                 arguments: Arguments,
             ): ExecutionResult<Output> {
                 for (uiResponse in uiResponses) {
@@ -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,8 +150,8 @@
     @Test
     fun multipleUpdate_sharesCache() {
         assertThat(UiSessions.getUiCacheOrNull(sessionId)).isNull()
-        sessionFactory.addSessions(object : Session {
-            override suspend fun onFinish(
+        sessionFactory.addExecutionSessions(object : ExecutionSession {
+            override suspend fun onExecute(
                 arguments: Arguments,
             ): ExecutionResult<Output> {
                 this.updateUi(remoteViewsUiResponse)
@@ -184,17 +184,17 @@
     fun multipleSession_haveTheirOwnCache() {
         val sessionId1 = "fakeSessionId1"
         val sessionId2 = "fakeSessionId2"
-        sessionFactory.addSessions(
-            object : Session {
-                override suspend fun onFinish(
+        sessionFactory.addExecutionSessions(
+            object : ExecutionSession {
+                override suspend fun onExecute(
                     arguments: Arguments,
                 ): ExecutionResult<Output> {
                     this.updateUi(remoteViewsUiResponse)
                     return ExecutionResult.Builder<Output>().build()
                 }
             },
-            object : Session {
-                override suspend fun onFinish(
+            object : ExecutionSession {
+                override suspend fun onExecute(
                     arguments: Arguments,
                 ): ExecutionResult<Output> {
                     this.updateUi(tileLayoutUiResponse)
@@ -254,7 +254,7 @@
         val oneShotCapability = FakeCapability.CapabilityBuilder().setId(
             "oneShotCapability",
         ).setExecutor(object : ActionExecutor<Arguments, Output> {
-            override suspend fun execute(arguments: Arguments): ExecutionResult<Output> {
+            override suspend fun onExecute(arguments: Arguments): ExecutionResult<Output> {
                 this.updateUi(remoteViewsUiResponse)
                 return ExecutionResult.Builder<Output>().build()
             }
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 babd6e9..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,21 +17,21 @@
 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.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.ParamProperty
+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
 
 private const val CAPABILITY_NAME = "actions.intent.FAKE_CAPABILITY"
 private val ACTION_SPEC = ActionSpecBuilder.ofCapabilityNamed(CAPABILITY_NAME)
-    .setDescriptor(FakeCapability.Property::class.java)
+    .setDescriptor(FakeCapability.Properties::class.java)
     .setArguments(FakeCapability.Arguments::class.java, FakeCapability.Arguments::Builder)
     .setOutput(FakeCapability.Output::class.java).bindOptionalParameter(
         "fieldOne",
@@ -42,8 +42,8 @@
     ).build()
 
 class FakeCapability private constructor() {
-    class Property(
-        val fieldOne: ParamProperty<StringValue>? = null,
+    class Properties(
+        val fieldOne: Property<StringValue>? = null,
     )
 
     class Arguments internal constructor(
@@ -62,20 +62,20 @@
 
     class Confirmation internal constructor()
 
-    interface Session : BaseSession<Arguments, Output> {
+    interface ExecutionSession : BaseExecutionSession<Arguments, Output> {
         val fieldOneListener: ValueListener<String>?
             get() = null
     }
 
     class CapabilityBuilder : Capability.Builder<
         CapabilityBuilder,
-        Property,
+        Properties,
         Arguments,
         Output,
         Confirmation,
-        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 {
@@ -88,18 +88,18 @@
             builder.build()
         }
 
-        private var fieldOne: ParamProperty<StringValue>? = null
+        private var fieldOne: Property<StringValue>? = null
 
-        fun setFieldOne(fieldOne: ParamProperty<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/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/bluetooth/integration-tests/testapp/build.gradle b/bluetooth/integration-tests/testapp/build.gradle
index 441d909..860d815 100644
--- a/bluetooth/integration-tests/testapp/build.gradle
+++ b/bluetooth/integration-tests/testapp/build.gradle
@@ -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/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/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index f3b5a89..1bea081 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
@@ -591,7 +590,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/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/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 9842cf0..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 = "34.0.0-rc3"
+    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/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/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/CameraQuirks.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CameraQuirks.kt
index d2fbf1e..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
@@ -47,6 +47,9 @@
 
         // 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())
         }
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/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/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/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/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/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/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/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-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/SurfaceRequestTest.kt
index badc058..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,12 @@
     }
 
     @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
@@ -385,7 +387,7 @@
     private fun createNewRequest(
         size: Size,
         dynamicRange: DynamicRange = DynamicRange.SDR,
-        expectedFrameRate: Range<Int>? = null,
+        expectedFrameRate: Range<Int> = SurfaceRequest.FRAME_RATE_RANGE_UNSPECIFIED,
         autoCleanup: Boolean = true,
         onInvalidated: () -> Unit = {},
     ): SurfaceRequest {
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 2664daf..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
@@ -230,7 +230,7 @@
                 streamSpec.getResolution(),
                 getCamera(),
                 streamSpec.getDynamicRange(),
-                /* expectedFrameRate= */null,
+                streamSpec.getExpectedFrameRateRange(),
                 this::notifyReset);
         mCurrentSurfaceRequest = surfaceRequest;
 
@@ -287,8 +287,7 @@
 
         // Send the app Surface to the app.
         mSessionDeferrableSurface = mCameraEdge.getDeferrableSurface();
-        mCurrentSurfaceRequest = appEdge.createSurfaceRequest(camera,
-                /* expectedFrameRateRange= */null);
+        mCurrentSurfaceRequest = appEdge.createSurfaceRequest(camera);
         if (mSurfaceProvider != null) {
             // Only send surface request if the provider is set.
             sendSurfaceRequest();
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 2b7e481..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,6 +87,16 @@
  */
 @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;
@@ -93,7 +104,6 @@
     @NonNull
     private final DynamicRange mDynamicRange;
 
-    @Nullable
     private final Range<Integer> mExpectedFrameRate;
     private final CameraInternal mCamera;
 
@@ -136,11 +146,11 @@
             @NonNull Size resolution,
             @NonNull CameraInternal camera,
             @NonNull Runnable onInvalidated) {
-        this(resolution, camera, DynamicRange.SDR, /*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.
      *
      */
@@ -149,7 +159,7 @@
             @NonNull Size resolution,
             @NonNull CameraInternal camera,
             @NonNull DynamicRange dynamicRange,
-            @Nullable Range<Integer> expectedFrameRate,
+            @NonNull Range<Integer> expectedFrameRate,
             @NonNull Runnable onInvalidated) {
         super();
         mResolution = resolution;
@@ -346,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/processing/SurfaceEdge.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEdge.java
index 84cd822..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 dynamic range and expected frame
-     * rate range with which the surface should operate.
-     */
-    @MainThread
-    @NonNull
-    public SurfaceRequest createSurfaceRequest(@NonNull CameraInternal cameraInternal,
-            @Nullable Range<Integer> expectedFrameRateRange) {
         checkMainThread();
         checkNotClosed();
         // TODO(b/238230154) figure out how to support HDR.
-        SurfaceRequest surfaceRequest = new SurfaceRequest(mStreamSpec.getResolution(),
-                cameraInternal, mStreamSpec.getDynamicRange(), expectedFrameRateRange,
+        SurfaceRequest surfaceRequest = new SurfaceRequest(
+                mStreamSpec.getResolution(),
+                cameraInternal,
+                mStreamSpec.getDynamicRange(),
+                mStreamSpec.getExpectedFrameRateRange(),
                 () -> mainThreadExecutor().execute(() -> {
                     if (!mIsClosed) {
                         invalidate();
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 218bd59..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)
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 5b5ced9..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(() -> {
@@ -631,7 +638,7 @@
                     resolution,
                     camera,
                     streamSpec.getDynamicRange(),
-                    targetFpsRange,
+                    expectedFrameRate,
                     onSurfaceInvalidated);
             mDeferrableSurface = mSurfaceRequest.getDeferrableSurface();
         }
@@ -644,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));
@@ -1031,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;
         }
@@ -1040,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
@@ -1068,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(
@@ -1077,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/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/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 315770c..647d7b5 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
@@ -124,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-alpha03"
+        const val compilerVersion: String = "1.4.5"
         private val minimumRuntimeVersion: String
             get() = runtimeVersionToMavenVersionTable[minimumRuntimeVersionInt] ?: "unknown"
     }
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 320d61f..3954218 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -1296,7 +1296,7 @@
   }
 
   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 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 boolean secureContent, 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);
   }
 
 }
@@ -1446,8 +1446,8 @@
   @androidx.compose.foundation.ExperimentalFoundationApi 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 getValue();
-    property public final androidx.compose.foundation.text2.input.TextFieldCharSequence value;
+    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> {
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 88597a5..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.toString(),
+                value = state.text.toString(),
                 visualTransformation = VisualTransformation.None,
                 innerTextField = it,
                 placeholder = null,
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
index 3c6d1c3..fe5e726 100644
--- 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
@@ -31,7 +31,10 @@
 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
@@ -59,6 +62,18 @@
     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(
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 061247d..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
@@ -228,7 +228,7 @@
         rule.onNodeWithTag(Tag).performTextInputSelection(TextRange(2))
 
         rule.runOnIdle {
-            assertThat(state.value.selectionInChars).isEqualTo(TextRange(2))
+            assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
         }
     }
 
@@ -290,20 +290,6 @@
         }
     }
 
-    @Test
-    fun passwordSemanticsAreSet_accordingToSecureContent() {
-        val state = TextFieldState()
-        rule.setContent {
-            BasicTextField2(
-                state = state,
-                secureContent = true,
-                modifier = Modifier.testTag(Tag)
-            )
-        }
-
-        rule.onNodeWithTag(Tag).assert(SemanticsMatcher.keyIsDefined(SemanticsProperties.Password))
-    }
-
     private fun SemanticsNodeInteraction.assertSelection(expected: TextRange) {
         val selection = fetchSemanticsNode().config
             .getOrNull(SemanticsProperties.TextSelectionRange)
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 9d4250e..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,16 +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.TextEditFilter
 import androidx.compose.foundation.text2.input.TextFieldBuffer.ChangeList
 import androidx.compose.foundation.text2.input.TextFieldBufferWithSelection
-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.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
@@ -55,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
@@ -63,9 +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.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
@@ -120,7 +130,7 @@
         rule.onNodeWithTag(Tag).performTextInput("World!")
 
         rule.runOnIdle {
-            assertThat(state.value.toString()).isEqualTo("Hello World!")
+            assertThat(state.text.toString()).isEqualTo("Hello World!")
         }
 
         rule.onNodeWithTag(Tag).assertTextEquals("Hello World!")
@@ -329,8 +339,8 @@
             performTextReplacement("Compose2")
             assertTextEquals("Compose2")
         }
-        assertThat(state1.value.toString()).isEqualTo("Compose")
-        assertThat(state2.value.toString()).isEqualTo("Compose2")
+        assertThat(state1.text.toString()).isEqualTo("Compose")
+        assertThat(state2.text.toString()).isEqualTo("Compose2")
     }
 
     @Test
@@ -865,6 +875,73 @@
         }
     }
 
+    @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)
 
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 148087d..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
@@ -173,7 +173,7 @@
         }
 
         rule.runOnIdle {
-            assertThat(state.value.toString()).isEqualTo("hello")
+            assertThat(state.text.toString()).isEqualTo("hello")
         }
     }
 
@@ -208,7 +208,7 @@
         }
 
         rule.runOnIdle {
-            assertThat(state.value.toString()).isEqualTo("hello")
+            assertThat(state.text.toString()).isEqualTo("hello")
         }
     }
 
@@ -242,7 +242,7 @@
 
         // assertThat selection happened
         rule.runOnIdle {
-            assertThat(state.value.selectionInChars).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/TextFieldCursorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldCursorTest.kt
index 2aa87be..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
@@ -108,7 +108,7 @@
     private var textLayoutResult: TextLayoutResult? = null
     private val cursorRect: Rect
         // assume selection is collapsed
-        get() = textLayoutResult?.getCursorRect(state.value.selectionInChars.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 }
@@ -575,7 +575,7 @@
                     textStyle = textStyle,
                     modifier = textFieldModifier.layout { measurable, constraints ->
                         // change the state during layout so draw can read the new state
-                        val currValue = state.value
+                        val currValue = state.text
                         if (currValue.isNotEmpty()) {
                             val newText = currValue.dropLast(1)
                             val 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 fed092c..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
@@ -623,13 +623,13 @@
 
         fun expectedText(text: String) {
             rule.runOnIdle {
-                assertThat(state.value.toString()).isEqualTo(text)
+                assertThat(state.text.toString()).isEqualTo(text)
             }
         }
 
         fun expectedSelection(selection: TextRange) {
             rule.runOnIdle {
-                assertThat(state.value.selectionInChars).isEqualTo(selection)
+                assertThat(state.text.selectionInChars).isEqualTo(selection)
             }
         }
     }
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 7661d74..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
@@ -401,7 +401,7 @@
         // move cursor to the end
         // TODO
         state.editProcessor.reset(
-            TextFieldCharSequence(state.value, selection = TextRange(longText.length))
+            TextFieldCharSequence(state.text, selection = TextRange(longText.length))
         )
 
         rule.runOnIdle {
@@ -426,7 +426,7 @@
 
         // move cursor to the end
         state.editProcessor.reset(
-            TextFieldCharSequence(state.value, selection = TextRange(longText.length))
+            TextFieldCharSequence(state.text, selection = TextRange(longText.length))
         )
 
         rule.runOnIdle {
@@ -454,7 +454,7 @@
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(scrollState.maxValue)
-            assertThat(state.value.selectionInChars).isEqualTo(TextRange(5))
+            assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
         }
     }
 
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 62a1def..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.toString()).isEqualTo("hello, world")
-            assertThat(restoredState.value.selectionInChars).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 5b75315..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
@@ -147,8 +147,8 @@
 
             connection.commitText("Hello", 0)
 
-            assertThat(state1.value.toString()).isEqualTo("")
-            assertThat(state2.value.toString()).isEqualTo("Hello")
+            assertThat(state1.text.toString()).isEqualTo("")
+            assertThat(state2.text.toString()).isEqualTo("Hello")
         }
     }
 
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
index 75cabf5..2b9bd1c 100644
--- 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
@@ -43,6 +43,8 @@
 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
@@ -159,11 +161,19 @@
         }
     }
 
+    val secureTextFieldModifier = modifier
+        .semantics(mergeDescendants = true) { password() }
+        .then(
+            if (revealLastTypedEnabled) {
+                secureTextFieldController.focusChangeModifier
+            } else {
+                Modifier
+            }
+        )
+
     BasicTextField2(
         state = state,
-        modifier = if (revealLastTypedEnabled) {
-            modifier.then(secureTextFieldController.focusChangeModifier)
-        } else modifier,
+        modifier = secureTextFieldModifier,
         enabled = enabled,
         readOnly = false,
         filter = if (revealLastTypedEnabled) {
@@ -185,7 +195,6 @@
         onTextLayout = onTextLayout,
         codepointTransformation = codepointTransformation,
         decorationBox = decorationBox,
-        secureContent = true
     )
 }
 
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 de7736c..b51170c 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
@@ -108,11 +108,6 @@
  * 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 secureContent Controls whether the content of this editor should be secured, for example,
- * if it's a password input field. Enabling this flag will disable context menu actions like cut,
- * copy, and paste for added security. It will also notify the accessibility service that the
- * editor may contain sensitive input. However, just turning on this flag is not enough to use this
- * editor as a password field. For password entry fields, please refer to [BasicSecureTextField].
  * @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
@@ -138,7 +133,6 @@
     cursorBrush: Brush = SolidColor(Color.Black),
     scrollState: ScrollState = rememberScrollState(),
     codepointTransformation: CodepointTransformation? = null,
-    secureContent: Boolean = false,
     decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
         @Composable { innerTextField -> innerTextField() }
 ) {
@@ -159,7 +153,7 @@
     val textLayoutState = remember {
         TextLayoutState(
             TextDelegate(
-                text = AnnotatedString(state.value.toString()),
+                text = AnnotatedString(state.text.toString()),
                 style = textStyle,
                 density = density,
                 fontFamilyResolver = fontFamilyResolver,
@@ -182,7 +176,6 @@
                 keyboardOptions = keyboardOptions,
                 keyboardActions = keyboardActions,
                 singleLine = singleLine,
-                secureContent = secureContent
             )
         )
         .focusable(interactionSource = interactionSource, enabled = enabled)
@@ -232,7 +225,7 @@
 
             Layout(modifier = coreModifiers) { _, constraints ->
                 val result = with(textLayoutState) {
-                    val visualText = state.value.toVisualText(codepointTransformation)
+                    val visualText = state.text.toVisualText(codepointTransformation)
                     layout(
                         text = AnnotatedString(visualText.toString()),
                         textStyle = textStyle,
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 ef350fa..9cd5e6a 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
@@ -40,7 +40,7 @@
     internal var editProcessor =
         EditProcessor(TextFieldCharSequence(initialText, initialSelectionInChars))
 
-    val value: TextFieldCharSequence
+    val text: TextFieldCharSequence
         get() = editProcessor.value
 
     /**
@@ -54,13 +54,13 @@
      * @see setTextAndSelectAll
      */
     inline fun edit(block: TextFieldBuffer.() -> TextEditResult) {
-        val mutableValue = startEdit(value)
+        val mutableValue = startEdit(text)
         val result = mutableValue.block()
         commitEdit(mutableValue, result)
     }
 
     override fun toString(): String =
-        "TextFieldState(selection=${value.selectionInChars}, text=\"$value\")"
+        "TextFieldState(selection=${text.selectionInChars}, text=\"$text\")"
 
     @Suppress("ShowingMemberInHiddenClass")
     @PublishedApi
@@ -70,7 +70,7 @@
     @Suppress("ShowingMemberInHiddenClass")
     @PublishedApi
     internal fun commitEdit(newValue: TextFieldBuffer, result: TextEditResult) {
-        val newSelection = result.calculateSelection(value, newValue)
+        val newSelection = result.calculateSelection(text, newValue)
         val finalValue = newValue.toTextFieldCharSequence(newSelection)
         editProcessor.reset(finalValue)
     }
@@ -84,9 +84,9 @@
     @Suppress("RedundantNullableReturnType")
     object Saver : androidx.compose.runtime.saveable.Saver<TextFieldState, Any> {
         override fun SaverScope.save(value: TextFieldState): Any? = listOf(
-            value.value.toString(),
-            value.value.selectionInChars.start,
-            value.value.selectionInChars.end
+            value.text.toString(),
+            value.text.selectionInChars.start,
+            value.text.selectionInChars.end
         )
 
         override fun restore(value: Any): TextFieldState? {
@@ -146,7 +146,7 @@
 
 @OptIn(ExperimentalFoundationApi::class)
 internal fun TextFieldState.deselect() {
-    if (!value.selectionInChars.collapsed) {
+    if (!text.selectionInChars.collapsed) {
         edit {
             selectCharsIn(TextRange.Zero)
         }
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 d04a716..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
@@ -184,7 +184,7 @@
 
         // region EditableTextInputSession
         override val value: TextFieldCharSequence
-            get() = state.value
+            get() = state.text
 
         private var filter: TextEditFilter? = initialFilter
 
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 ffe9ad8..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
@@ -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,7 +204,7 @@
 
     override fun ContentDrawScope.draw() {
         drawContent()
-        val value = textFieldState.value
+        val value = textFieldState.text
         val textLayoutResult = textLayoutState.layoutResult ?: return
 
         if (value.selectionInChars.collapsed) {
@@ -224,7 +224,7 @@
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
-        val currSelection = textFieldState.value.selectionInChars
+        val currSelection = textFieldState.text.selectionInChars
         val offsetToFollow = when {
             currSelection.start != previousSelection.start -> currSelection.start
             currSelection.end != previousSelection.end -> currSelection.end
@@ -260,7 +260,7 @@
         measurable: Measurable,
         constraints: Constraints
     ): MeasureResult {
-        val value = textFieldState.value
+        val value = textFieldState.text
         val offsetToFollow = when {
             value.selectionInChars.start != previousSelection.start -> value.selectionInChars.start
             value.selectionInChars.end != previousSelection.end -> value.selectionInChars.end
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 38f88b4..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,6 +17,7 @@
 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
@@ -25,7 +26,6 @@
 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
@@ -36,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
@@ -53,7 +54,6 @@
 import androidx.compose.ui.semantics.imeAction
 import androidx.compose.ui.semantics.insertTextAtCursor
 import androidx.compose.ui.semantics.onClick
-import androidx.compose.ui.semantics.password
 import androidx.compose.ui.semantics.performImeAction
 import androidx.compose.ui.semantics.setSelection
 import androidx.compose.ui.semantics.setText
@@ -64,7 +64,6 @@
 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
@@ -84,7 +83,6 @@
     private val keyboardOptions: KeyboardOptions,
     private val keyboardActions: KeyboardActions,
     private val singleLine: Boolean,
-    private val secureContent: Boolean
 ) : ModifierNodeElement<TextFieldDecoratorModifierNode>() {
     override fun create(): TextFieldDecoratorModifierNode = TextFieldDecoratorModifierNode(
         textFieldState = textFieldState,
@@ -96,7 +94,6 @@
         keyboardOptions = keyboardOptions,
         keyboardActions = keyboardActions,
         singleLine = singleLine,
-        secureContent = secureContent,
     )
 
     override fun update(node: TextFieldDecoratorModifierNode): TextFieldDecoratorModifierNode {
@@ -110,7 +107,6 @@
             keyboardOptions = keyboardOptions,
             keyboardActions = keyboardActions,
             singleLine = singleLine,
-            secureContent = secureContent,
         )
         return node
     }
@@ -132,8 +128,7 @@
     keyboardOptions: KeyboardOptions,
     var keyboardActions: KeyboardActions,
     var singleLine: Boolean,
-    var secureContent: Boolean,
-) : Modifier.Node(),
+) : DelegatingNode(),
     SemanticsModifierNode,
     FocusRequesterModifierNode,
     FocusEventModifierNode,
@@ -142,6 +137,19 @@
     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
 
@@ -149,7 +157,6 @@
     private var lastText: CharSequence? = null
     private var lastSelection: TextRange? = null
     private var lastEnabled: Boolean = enabled
-    private var lastSecureContent: Boolean = secureContent
 
     private var isFocused: Boolean = false
     private var semanticsConfigurationCache: SemanticsConfiguration? = null
@@ -212,7 +219,6 @@
         keyboardOptions: KeyboardOptions,
         keyboardActions: KeyboardActions,
         singleLine: Boolean,
-        secureContent: Boolean,
     ) {
         // Find the diff: current previous and new values before updating current.
         val previousWriteable = this.enabled && !this.readOnly
@@ -230,7 +236,6 @@
         this.keyboardOptions = keyboardOptions.withDefaultsFrom(filter?.keyboardOptions)
         this.keyboardActions = keyboardActions
         this.singleLine = singleLine
-        this.secureContent = secureContent
 
         // React to diff.
         // If made writable while focused, or we got a completely new state instance,
@@ -263,14 +268,13 @@
     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 ||
                 !value.contentEquals(lastText) ||
                 lastSelection != value.selectionInChars ||
-                lastEnabled != enabled ||
-                lastSecureContent != secureContent
+                lastEnabled != enabled
             ) {
                 localSemantics = generateSemantics(value, value.selectionInChars)
             }
@@ -311,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 {
@@ -352,7 +354,6 @@
             textSelectionRange = selection
             imeAction = keyboardOptions.imeAction
             if (!enabled) disabled()
-            if (secureContent) password()
 
             setText { text ->
                 textFieldState.editProcessor.update(
@@ -379,7 +380,7 @@
                     // reset is required to make sure IME gets the update.
                     textFieldState.editProcessor.reset(
                         TextFieldCharSequence(
-                            text = textFieldState.value,
+                            text = textFieldState.text,
                             selection = TextRange(start, end)
                         )
                     )
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 7c4310a..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
@@ -78,7 +78,7 @@
      * [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]
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 792ccef..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
@@ -35,8 +35,8 @@
         val restoredState = TextFieldState.Saver.restore(saved)
 
         assertNotNull(restoredState)
-        assertThat(restoredState.value.toString()).isEqualTo("hello, world")
-        assertThat(restoredState.value.selectionInChars).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 8079447..d068e21 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
@@ -32,7 +32,7 @@
 
     @Test
     fun initialValue() {
-        assertThat(state.value.toString()).isEqualTo("")
+        assertThat(state.text.toString()).isEqualTo("")
     }
 
     @Test
@@ -46,7 +46,7 @@
             }
         }
 
-        assertThat(state.value.toString()).isEmpty()
+        assertThat(state.text.toString()).isEmpty()
     }
 
     @Test
@@ -65,14 +65,14 @@
             replace(0, 0, "hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
     fun edit_replace_doesNotChangeStateUntilReturn() {
         state.edit {
             replace(0, 0, "hello")
-            assertThat(state.value.toString()).isEmpty()
+            assertThat(state.text.toString()).isEmpty()
             placeCursorAtEnd()
         }
     }
@@ -85,10 +85,10 @@
             replace(5, 5, " ")
             replace(6, 11, "Compose")
             assertThat(toString()).isEqualTo("hello Compose")
-            assertThat(state.value.toString()).isEmpty()
+            assertThat(state.text.toString()).isEmpty()
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("hello Compose")
+        assertThat(state.text.toString()).isEqualTo("hello Compose")
     }
 
     @Test
@@ -97,7 +97,7 @@
             replace(0, 0, "hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(5))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(5))
     }
 
     @Test
@@ -106,7 +106,7 @@
             replace(0, 0, "hello")
             placeCursorBeforeCharAt(2)
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(2))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
     }
 
     @Test
@@ -128,7 +128,7 @@
             replace(0, 0, "hello")
             placeCursorBeforeCodepointAt(2)
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(2))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(2))
     }
 
     @Test
@@ -150,7 +150,7 @@
             replace(0, 0, "hello")
             selectAll()
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(0, 5))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
     }
 
     @Test
@@ -159,7 +159,7 @@
             replace(0, 0, "hello")
             selectCharsIn(TextRange(1, 4))
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(1, 4))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
     }
 
     @Test
@@ -187,7 +187,7 @@
             replace(0, 0, "hello")
             selectCodepointsIn(TextRange(1, 4))
         }
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(1, 4))
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(1, 4))
     }
 
     @Test
@@ -221,7 +221,7 @@
             assertThat(toString()).isEqualTo("hello world")
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("hello world")
+        assertThat(state.text.toString()).isEqualTo("hello world")
     }
 
     @Test
@@ -230,7 +230,7 @@
             append('c')
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("c")
+        assertThat(state.text.toString()).isEqualTo("c")
     }
 
     @Test
@@ -239,7 +239,7 @@
             append("hello")
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
@@ -248,21 +248,21 @@
             append("hello world", 0, 5)
             placeCursorAtEnd()
         }
-        assertThat(state.value.toString()).isEqualTo("hello")
+        assertThat(state.text.toString()).isEqualTo("hello")
     }
 
     @Test
     fun setTextAndPlaceCursorAtEnd_works() {
         state.setTextAndPlaceCursorAtEnd("Hello")
-        assertThat(state.value.toString()).isEqualTo("Hello")
-        assertThat(state.value.selectionInChars).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.toString()).isEqualTo("Hello")
-        assertThat(state.value.selectionInChars).isEqualTo(TextRange(0, 5))
+        assertThat(state.text.toString()).isEqualTo("Hello")
+        assertThat(state.text.selectionInChars).isEqualTo(TextRange(0, 5))
     }
 
     @Test
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/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/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/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 17391e0..ee20288 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -25,7 +25,6 @@
 import android.os.Handler
 import android.os.Looper
 import android.os.SystemClock
-import android.text.SpannableString
 import android.util.Log
 import android.view.MotionEvent
 import android.view.View
@@ -724,17 +723,6 @@
         }
     }
 
-    private fun isScreenReaderFocusable(
-        node: SemanticsNode
-    ): Boolean {
-        val isSpeakingNode = node.infoContentDescriptionOrNull != null ||
-            getInfoText(node) != null || getInfoStateDescriptionOrNull(node) != null ||
-            getInfoIsCheckable(node)
-
-        return node.unmergedConfig.isMergingSemanticsOfDescendants ||
-            node.isUnmergedLeafNode && isSpeakingNode
-    }
-
     @VisibleForTesting
     @OptIn(ExperimentalComposeUiApi::class)
     fun populateAccessibilityNodeInfoProperties(
@@ -742,6 +730,15 @@
         info: AccessibilityNodeInfoCompat,
         semanticsNode: SemanticsNode
     ) {
+        val isUnmergedLeafNode =
+            !semanticsNode.isFake &&
+                semanticsNode.replacedChildren.isEmpty() &&
+                semanticsNode.layoutNode.findClosestParentNode {
+                    it.outerSemantics
+                        ?.collapsedSemanticsConfiguration()
+                        ?.isMergingSemanticsOfDescendants == true
+                } == null
+
         // set classname
         info.className = ClassName
         val role = semanticsNode.unmergedConfig.getOrNull(SemanticsProperties.Role)
@@ -756,7 +753,7 @@
                     // Images are often minor children of larger widgets, so we only want to
                     // announce the Image role when the image itself is focusable.
                     if (role != Role.Image ||
-                        semanticsNode.isUnmergedLeafNode ||
+                        isUnmergedLeafNode ||
                         semanticsNode.unmergedConfig.isMergingSemanticsOfDescendants
                     ) {
                         info.className = className
@@ -801,17 +798,39 @@
 
         setText(semanticsNode, info)
         setContentInvalid(semanticsNode, info)
-        setStateDescription(semanticsNode, info)
-        setIsCheckable(semanticsNode, info)
 
+        info.stateDescription =
+            semanticsNode.unmergedConfig.getOrNull(SemanticsProperties.StateDescription)
         val toggleState = semanticsNode.unmergedConfig.getOrNull(
             SemanticsProperties.ToggleableState
         )
         toggleState?.let {
-            if (toggleState == ToggleableState.On) {
-                info.isChecked = true
-            } else if (toggleState == ToggleableState.Off) {
-                info.isChecked = false
+            info.isCheckable = true
+            when (it) {
+                ToggleableState.On -> {
+                    info.isChecked = true
+                    // Unfortunately, talback has a bug of using "checked", so we set state
+                    // description here
+                    if (role == Role.Switch && info.stateDescription == null) {
+                        info.stateDescription = view.context.resources.getString(R.string.on)
+                    }
+                }
+
+                ToggleableState.Off -> {
+                    info.isChecked = false
+                    // Unfortunately, talkback has a bug of using "not checked", so we set state
+                    // description here
+                    if (role == Role.Switch && info.stateDescription == null) {
+                        info.stateDescription = view.context.resources.getString(R.string.off)
+                    }
+                }
+
+                ToggleableState.Indeterminate -> {
+                    if (info.stateDescription == null) {
+                        info.stateDescription =
+                            view.context.resources.getString(R.string.indeterminate)
+                    }
+                }
             }
         }
         semanticsNode.unmergedConfig.getOrNull(SemanticsProperties.Selected)?.let {
@@ -819,7 +838,18 @@
                 // Tab in native android uses selected property
                 info.isSelected = it
             } else {
+                info.isCheckable = true
                 info.isChecked = it
+                if (info.stateDescription == null) {
+                    // If a radio entry (radio button + text) is selectable, it won't have the role
+                    // RadioButton, so if we use info.isCheckable/info.isChecked, talkback will say
+                    // "checked/not checked" instead "selected/note selected".
+                    info.stateDescription = if (it) {
+                        view.context.resources.getString(R.string.selected)
+                    } else {
+                        view.context.resources.getString(R.string.not_selected)
+                    }
+                }
             }
         }
 
@@ -1035,6 +1065,29 @@
                     rangeInfo.range.endInclusive,
                     rangeInfo.current
                 )
+                // let's set state description here and use state description change events.
+                // otherwise, we need to send out type_view_selected event, as the old android
+                // versions do. But the support for type_view_selected event for progress bars
+                // maybe deprecated in talkback in the future.
+                if (info.stateDescription == null) {
+                    val valueRange = rangeInfo.range
+                    val progress = (
+                        if (valueRange.endInclusive - valueRange.start == 0f) 0f
+                        else (rangeInfo.current - valueRange.start) /
+                            (valueRange.endInclusive - valueRange.start)
+                        ).coerceIn(0f, 1f)
+
+                    // We only display 0% or 100% when it is exactly 0% or 100%.
+                    val percent = when (progress) {
+                        0f -> 0
+                        1f -> 100
+                        else -> (progress * 100).roundToInt().coerceIn(1, 99)
+                    }
+                    info.stateDescription =
+                        view.context.resources.getString(R.string.template_percent, percent)
+                }
+            } else if (info.stateDescription == null) {
+                info.stateDescription = view.context.resources.getString(R.string.in_progress)
             }
             if (semanticsNode.unmergedConfig.contains(SemanticsActions.SetProgress) &&
                 semanticsNode.enabled()
@@ -1210,7 +1263,12 @@
             }
         }
 
-        info.isScreenReaderFocusable = isScreenReaderFocusable(semanticsNode)
+        val isSpeakingNode = info.contentDescription != null || info.text != null ||
+            info.hintText != null || info.stateDescription != null || info.isCheckable
+
+        info.isScreenReaderFocusable =
+            semanticsNode.unmergedConfig.isMergingSemanticsOfDescendants ||
+                isUnmergedLeafNode && isSpeakingNode
 
         if (idToBeforeMap[virtualViewId] != null) {
             idToBeforeMap[virtualViewId]?.let { info.setTraversalBefore(view, it) }
@@ -1235,131 +1293,10 @@
         }
     }
 
-    private fun getInfoStateDescriptionOrNull(
-        node: SemanticsNode
-    ): String? {
-        var stateDescription = node.unmergedConfig.getOrNull(SemanticsProperties.StateDescription)
-        val toggleState = node.unmergedConfig.getOrNull(SemanticsProperties.ToggleableState)
-        val role = node.unmergedConfig.getOrNull(SemanticsProperties.Role)
-
-        // Check toggle state and retrieve description accordingly
-        toggleState?.let {
-            when (it) {
-                ToggleableState.On -> {
-                    // Unfortunately, talkback has a bug of using "checked", so we set state
-                    // description here
-                    if (role == Role.Switch && stateDescription == null) {
-                        stateDescription = view.context.resources.getString(R.string.on)
-                    }
-                }
-
-                ToggleableState.Off -> {
-                    // Unfortunately, talkback has a bug of using "not checked", so we set state
-                    // description here
-                    if (role == Role.Switch && stateDescription == null) {
-                        stateDescription = view.context.resources.getString(R.string.off)
-                    }
-                }
-
-                ToggleableState.Indeterminate -> {
-                    if (stateDescription == null) {
-                        stateDescription =
-                            view.context.resources.getString(R.string.indeterminate)
-                    }
-                }
-            }
-        }
-
-        // Check Selected property and retrieve description accordingly
-        node.unmergedConfig.getOrNull(SemanticsProperties.Selected)?.let {
-            if (role != Role.Tab) {
-                if (stateDescription == null) {
-                    // If a radio entry (radio button + text) is selectable, it won't have the role
-                    // RadioButton, so if we use info.isCheckable/info.isChecked, talkback will say
-                    // "checked/not checked" instead "selected/note selected".
-                    stateDescription = if (it) {
-                        view.context.resources.getString(R.string.selected)
-                    } else {
-                        view.context.resources.getString(R.string.not_selected)
-                    }
-                }
-            }
-        }
-
-        // Check if a node has progress bar range info and retrieve description accordingly
-        val rangeInfo =
-            node.unmergedConfig.getOrNull(SemanticsProperties.ProgressBarRangeInfo)
-        rangeInfo?.let {
-            // let's set state description here and use state description change events.
-            // otherwise, we need to send out type_view_selected event, as the old android
-            // versions do. But the support for type_view_selected event for progress bars
-            // maybe deprecated in talkback in the future.
-            if (rangeInfo !== ProgressBarRangeInfo.Indeterminate) {
-                if (stateDescription == null) {
-                    val valueRange = rangeInfo.range
-                    val progress = (
-                        if (valueRange.endInclusive - valueRange.start == 0f) 0f
-                        else (rangeInfo.current - valueRange.start) /
-                            (valueRange.endInclusive - valueRange.start)
-                        ).coerceIn(0f, 1f)
-
-                    // We only display 0% or 100% when it is exactly 0% or 100%.
-                    val percent = when (progress) {
-                        0f -> 0
-                        1f -> 100
-                        else -> (progress * 100).roundToInt().coerceIn(1, 99)
-                    }
-                    stateDescription =
-                        view.context.resources.getString(R.string.template_percent, percent)
-                }
-            } else if (stateDescription == null) {
-                stateDescription = view.context.resources.getString(R.string.in_progress)
-            }
-        }
-
-        return stateDescription
-    }
-
-    private fun setStateDescription(
+    private fun setText(
         node: SemanticsNode,
         info: AccessibilityNodeInfoCompat,
     ) {
-        info.stateDescription = getInfoStateDescriptionOrNull(node)
-    }
-
-    private fun getInfoIsCheckable(
-        node: SemanticsNode
-    ): Boolean {
-        var isCheckable = false
-        val toggleState = node.unmergedConfig.getOrNull(SemanticsProperties.ToggleableState)
-        val role = node.unmergedConfig.getOrNull(SemanticsProperties.Role)
-
-        toggleState?.let {
-            isCheckable = true
-        }
-
-        node.unmergedConfig.getOrNull(SemanticsProperties.Selected)?.let {
-            if (role != Role.Tab) {
-                isCheckable = true
-            }
-        }
-
-        return isCheckable
-    }
-
-    private fun setIsCheckable(
-        node: SemanticsNode,
-        info: AccessibilityNodeInfoCompat
-    ) {
-        info.isCheckable = getInfoIsCheckable(node)
-    }
-
-    // This needs to be here instead of around line 3000 because we need access to the `view`
-    // that is inside the `AndroidComposeViewAccessibilityDelegateCompat` class
-    @OptIn(InternalTextApi::class)
-    private fun getInfoText(
-        node: SemanticsNode
-    ): SpannableString? {
         val fontFamilyResolver: FontFamily.Resolver = view.fontFamilyResolver
         val editableTextToAssign = trimToSize(
             node.unmergedConfig.getTextForTextField()
@@ -1380,14 +1317,8 @@
                 ),
             ParcelSafeTextLength
         )
-        return editableTextToAssign ?: textToAssign
-    }
 
-    private fun setText(
-        node: SemanticsNode,
-        info: AccessibilityNodeInfoCompat,
-    ) {
-        info.text = getInfoText(node)
+        info.text = editableTextToAssign ?: textToAssign
     }
 
     /**
@@ -2817,10 +2748,10 @@
         }
         if (bufferedContentCaptureDisappearedNodes.isNotEmpty()) {
             session.notifyViewsDisappeared(
-                bufferedContentCaptureDisappearedNodes
-                    .toList()
-                    .fastMap { it.toLong() }
-                    .toLongArray())
+                    bufferedContentCaptureDisappearedNodes
+                        .toList()
+                        .fastMap { it.toLong() }
+                        .toLongArray())
             bufferedContentCaptureDisappearedNodes.clear()
         }
     }
@@ -3277,9 +3208,6 @@
         return false
     }
 
-private val SemanticsNode.infoContentDescriptionOrNull get() = this.unmergedConfig.getOrNull(
-    SemanticsProperties.ContentDescription)?.firstOrNull()
-
 @OptIn(ExperimentalComposeUiApi::class)
 private fun SemanticsNode.excludeLineAndPageGranularities(): Boolean {
     // text field that is not in focus
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
index c56a5d2..ab6678e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
@@ -78,13 +78,6 @@
 
     internal val unmergedConfig = outerSemanticsNode.collapsedSemanticsConfiguration()
 
-    internal var isUnmergedLeafNode =
-        !isFake && replacedChildren.isEmpty() && layoutNode.findClosestParentNode {
-            it.outerSemantics
-                ?.collapsedSemanticsConfiguration()
-                ?.isMergingSemanticsOfDescendants == true
-        } == null
-
     /**
      * The [LayoutInfo] that this is associated with.
      */
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 5190382..3d50674 100644
--- a/constraintlayout/constraintlayout-compose/api/current.txt
+++ b/constraintlayout/constraintlayout-compose/api/current.txt
@@ -442,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 c230eb2..92a3feb 100644
--- a/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt
+++ b/constraintlayout/constraintlayout-compose/api/public_plus_experimental_current.txt
@@ -335,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();
@@ -617,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 4611a20..6038cb7 100644
--- a/constraintlayout/constraintlayout-compose/api/restricted_current.txt
+++ b/constraintlayout/constraintlayout-compose/api/restricted_current.txt
@@ -558,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/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/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/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 ddaf821..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)
@@ -219,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"
@@ -693,7 +706,9 @@
         testFile.deleteIfExists()
         val dataStore = newDataStore(
             serializerConfig = TestingSerializerConfig(defaultValue = 99),
-            scope = dataStoreScope)
+            scope = dataStoreScope
+        )
+
         assertThat(dataStore.data.first()).isEqualTo(99)
     }
 
@@ -877,6 +892,7 @@
             file = testIO.newTempFile(),
             scope = datastoreScope.backgroundScope
         )
+
         suspend fun <R> runAndPumpInStore(block: suspend () -> R): R {
             val async = datastoreScope.async { block() }
             datastoreScope.runCurrent()
@@ -958,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 b365438..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 {
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index d905952..59d4db0 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -804,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
@@ -1011,4 +1012,19 @@
 \$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'\.
\ No newline at end of file
+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/docs-public/build.gradle b/docs-public/build.gradle
index 66b74fc0..6a2a82b 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -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/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 763a9bb..fb7c81e 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PostponedTransitionTest.kt
@@ -1049,6 +1049,43 @@
     }
 
     @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)
@@ -1420,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 06729a3..53224f7 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -2855,6 +2855,9 @@
      */
     public final void postponeEnterTransition(long duration, @NonNull TimeUnit timeUnit) {
         ensureAnimationInfo().mEnterTransitionPostponed = true;
+        if (mPostponedHandler != null) {
+            mPostponedHandler.removeCallbacks(mPostponedDurationRunnable);
+        }
         if (mFragmentManager != null) {
             mPostponedHandler = mFragmentManager.getHost().getHandler();
         } else {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index c9987b2..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,8 +29,8 @@
 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"
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 5aa9291..0150fc4 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -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/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/lowlatency/CanvasFrontBufferedRendererTest.kt
index d3e0053..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
@@ -637,6 +637,8 @@
 
     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 instanceson
-        !(Build.MODEL.contains("gphone") && Build.VERSION.SDK_INT == 33)
+        // 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/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/libraryversions.toml b/libraryversions.toml
index 8ae0496..f3c44a4 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -20,8 +20,9 @@
 CAR_APP = "1.4.0-alpha01"
 COLLECTION = "1.3.0-alpha05"
 COMPOSE = "1.5.0-alpha03"
-COMPOSE_COMPILER = "1.4.4"
+COMPOSE_COMPILER = "1.4.5"
 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"
@@ -54,7 +55,7 @@
 EMOJI2 = "1.4.0-beta02"
 ENTERPRISE = "1.1.0-rc01"
 EXIFINTERFACE = "1.4.0-alpha01"
-FRAGMENT = "1.6.0-alpha10"
+FRAGMENT = "1.6.0-beta01"
 FUTURES = "1.2.0-alpha01"
 GLANCE = "1.0.0-alpha06"
 GLANCE_TEMPLATE = "1.0.0-alpha01"
@@ -85,7 +86,7 @@
 MEDIA2 = "1.3.0-alpha01"
 MEDIAROUTER = "1.5.0-alpha01"
 METRICS = "1.0.0-alpha05"
-NAVIGATION = "2.6.0-alpha10"
+NAVIGATION = "2.6.0-beta01"
 PAGING = "3.2.0-alpha05"
 PAGING_COMPOSE = "1.0.0-alpha19"
 PALETTE = "1.1.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/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-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-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/playground-common/playground.properties b/playground-common/playground.properties
index 306f1ab..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.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..c17bdce 100644
--- a/privacysandbox/tools/tools-apicompiler/build.gradle
+++ b/privacysandbox/tools/tools-apicompiler/build.gradle
@@ -46,7 +46,7 @@
             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 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)
diff --git a/privacysandbox/tools/tools-apigenerator/build.gradle b/privacysandbox/tools/tools-apigenerator/build.gradle
index b509312..afe4b88 100644
--- a/privacysandbox/tools/tools-apigenerator/build.gradle
+++ b/privacysandbox/tools/tools-apigenerator/build.gradle
@@ -53,7 +53,7 @@
             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 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)
diff --git a/privacysandbox/tools/tools-core/build.gradle b/privacysandbox/tools/tools-core/build.gradle
index a1b06db..7f2ce6b 100644
--- a/privacysandbox/tools/tools-core/build.gradle
+++ b/privacysandbox/tools/tools-core/build.gradle
@@ -43,7 +43,7 @@
             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 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)
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/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/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 d9e03c2..51235a5 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -519,6 +519,7 @@
 includeProject(":compose:material", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3", [BuildType.COMPOSE])
 includeProject(":compose:material3:benchmark", [BuildType.COMPOSE])
+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])
@@ -629,6 +630,7 @@
 includeProject(":customview:customview", [BuildType.MAIN])
 includeProject(":customview:customview-poolingcontainer", [BuildType.MAIN, BuildType.COMPOSE])
 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])
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/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 40c640c..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)
+                )
+            }
         }
     }
 
@@ -93,4 +119,11 @@
     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 03bad11..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
@@ -62,6 +72,12 @@
      */
     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()
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 320c661..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,6 +17,7 @@
 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
@@ -26,16 +27,36 @@
 
 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()
+            }
         }
     }
 
@@ -59,9 +80,10 @@
 
     override fun getStorage(
         serializerConfig: TestingSerializerConfig,
+        coordinatorProducer: () -> InterProcessCoordinator,
         futureFile: () -> TestFile
     ): Storage<Byte> {
-        return FileStorage(TestingSerializer(serializerConfig)) {
+        return FileStorage(TestingSerializer(serializerConfig), { coordinatorProducer() }) {
             (futureFile() as JavaIOFile).file
         }
     }
@@ -90,6 +112,12 @@
     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-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/tv/tv-material/api/public_plus_experimental_current.txt b/tv/tv-material/api/public_plus_experimental_current.txt
index 26b688f..3f5fc27 100644
--- a/tv/tv-material/api/public_plus_experimental_current.txt
+++ b/tv/tv-material/api/public_plus_experimental_current.txt
@@ -92,6 +92,20 @@
     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 {
   }
 
@@ -538,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/CardTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/CardTest.kt
index 3ea23a8..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
@@ -471,10 +471,8 @@
 }
 
 private const val CardTag = "card"
-private const val StandardCardTag = "standard-card"
 private const val CompactCardTag = "compact-card"
 private const val ClassicCardTag = "classic-card"
-private const val WideCardTag = "wide-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
index 9e6d21a..9cf007a 100644
--- a/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonScreenshotTest.kt
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/IconButtonScreenshotTest.kt
@@ -216,7 +216,7 @@
         rule.setContent {
             LightMaterialTheme {
                 localInputModeManager = LocalInputModeManager.current
-                Box(Modifier.sizeIn(minWidth = 50.dp, minHeight = 50.dp).testTag(wrapperTestTag)) {
+                Box(Modifier.sizeIn(minWidth = 52.dp, minHeight = 52.dp).testTag(wrapperTestTag)) {
                     IconButton(
                         onClick = { /* doSomething() */ },
                         modifier = Modifier
@@ -246,7 +246,7 @@
         rule.setContent {
             DarkMaterialTheme {
                 localInputModeManager = LocalInputModeManager.current
-                Box(Modifier.sizeIn(minWidth = 50.dp, minHeight = 50.dp).testTag(wrapperTestTag)) {
+                Box(Modifier.sizeIn(minWidth = 52.dp, minHeight = 52.dp).testTag(wrapperTestTag)) {
                     IconButton(
                         onClick = { /* doSomething() */ },
                         modifier = Modifier
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/ButtonStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ButtonStyles.kt
index 75e56dd..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
@@ -272,6 +313,15 @@
     )
 
 @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,
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 53add8d..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
@@ -30,7 +30,6 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -325,19 +324,7 @@
 }
 
 @Composable
-private fun CardContent(
-    title: @Composable () -> Unit,
-    subtitle: @Composable () -> Unit = {},
-    description: @Composable () -> Unit = {},
-    contentColor: Color
-) {
-    CompositionLocalProvider(LocalContentColor provides contentColor) {
-        CardContent(title, subtitle, description)
-    }
-}
-
-@Composable
-private fun CardContent(
+internal fun CardContent(
     title: @Composable () -> Unit,
     subtitle: @Composable () -> Unit = {},
     description: @Composable () -> Unit = {}
@@ -399,22 +386,6 @@
     )
 
     /**
-     * Returns the content color [Color] from the colors [CardColors] for different
-     * interaction states.
-     */
-    internal fun contentColor(
-        focused: Boolean,
-        pressed: Boolean,
-        colors: CardColors
-    ): Color {
-        return when {
-            focused -> colors.focusedContentColor
-            pressed -> colors.pressedContentColor
-            else -> colors.contentColor
-        }
-    }
-
-    /**
      * 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.
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/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/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/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt
new file mode 100644
index 0000000..0b3bb8d
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidAndroidTest/kotlin/androidx/wear/compose/material3/Screenshot.kt
@@ -0,0 +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.compose.material3
+
+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/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 eed72d2..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;
@@ -1049,6 +1050,25 @@
                 bindRecursively(
                         dynamicNode.getInput(), animationNode.getInputCallback(), resultBuilder);
                 break;
+            case CONDITIONAL_OP:
+                ConditionalOpNode<Integer> conditionalNode = new ConditionalOpNode<>(consumer);
+
+                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");
             default:
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/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 f66fa06..81a51e5 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -99,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();
   }
@@ -115,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();
   }
 
@@ -176,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 {
@@ -241,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 bee2cf9..a95e751 100644
--- a/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
@@ -99,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();
   }
@@ -115,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();
   }
 
@@ -176,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 {
@@ -241,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 f66fa06..81a51e5 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -99,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();
   }
@@ -115,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();
   }
 
@@ -176,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 {
@@ -241,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/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/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/DynamicFloatTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
index b178ff8..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,7 +17,9 @@
 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;
@@ -26,207 +28,225 @@
 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()
-          .setAnimationParameters(
-                  new AnimationParameters.Builder()
-                          .setDurationMillis(2)
-                          .setDelayMillis(1)
-                          .build())
-          .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().build())
-                .toString())
-        .isEqualTo(
-            "AnimatableFixedFloat{fromValue=1.0, toValue=2.0, animationSpec=AnimationSpec{"
-                + "animationParameters=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()
-                            .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 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/build.gradle b/wear/protolayout/protolayout-material/build.gradle
index 8d0c69d7..042384d 100644
--- a/wear/protolayout/protolayout-material/build.gradle
+++ b/wear/protolayout/protolayout-material/build.gradle
@@ -25,9 +25,8 @@
 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)
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 c9e3f38..fe23db4 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -142,6 +142,15 @@
   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 {
@@ -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 e270735..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
@@ -666,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")
@@ -683,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")
@@ -700,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")
@@ -716,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")
@@ -733,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")
@@ -747,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
@@ -770,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
@@ -794,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(
@@ -825,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(
@@ -899,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)
@@ -908,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) {
@@ -928,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
@@ -949,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) {
@@ -965,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)
@@ -976,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)
@@ -999,7 +941,6 @@
     /**
      * Sets visibility for resources tracked by the pipeline and plays / stops any affected
      * animations.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @UiThread
@@ -1031,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
@@ -1064,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() {
@@ -1082,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/inflater/ProtoLayoutInflaterTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
index 3aa3e5a..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
@@ -131,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;
@@ -1805,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();
         }
@@ -1837,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 =
@@ -1860,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();
         }
diff --git a/wear/protolayout/protolayout/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout/api/public_plus_experimental_current.txt
index 2c913e6..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
@@ -734,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();
@@ -746,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);
@@ -760,6 +763,7 @@
     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();
@@ -774,6 +778,7 @@
     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);
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 7e98f63a..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));
@@ -698,6 +755,97 @@
     }
 
     /**
+     * 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
@@ -924,6 +1072,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
@@ -1138,6 +1298,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(9, marqueeIterations);
+                return this;
+            }
+
             @Override
             @NonNull
             public Text build() {
@@ -2466,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
@@ -2615,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 600f72d..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
@@ -196,7 +196,7 @@
     public static final int SEMANTICS_ROLE_NONE = 0;
 
     /**
-     * The element is an {@link androidx.wear.protolayout.LayoutElementBuilders.Image}.
+     * The element is an image.
      *
      * @since 1.2
      */
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-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 300a829..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
@@ -551,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"),
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 b92c323..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
@@ -724,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 ->
@@ -803,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,
@@ -821,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/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/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-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/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;
+        }
+    }
 }